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 <ardour/route.h>
22 #include <ardour/automation_control.h>
23 #include <pbd/memento_command.h>
24 #include <gtkmm2ext/barcontroller.h>
26 #include "ardour_ui.h"
27 #include "automation_time_axis.h"
28 #include "automation_streamview.h"
29 #include "route_time_axis.h"
30 #include "automation_line.h"
31 #include "public_editor.h"
32 #include "simplerect.h"
33 #include "selection.h"
34 #include "rgb_macros.h"
35 #include "automation_selectable.h"
36 #include "point_selection.h"
37 #include "canvas_impl.h"
42 using namespace ARDOUR;
45 using namespace Gtkmm2ext;
46 using namespace Editing;
48 Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
49 bool AutomationTimeAxisView::have_name_font = false;
50 const string AutomationTimeAxisView::state_node_name = "AutomationChild";
53 /** \a a the automatable object this time axis is to display data for.
54 * For route/track automation (e.g. gain) pass the route for both \r and \a.
55 * For route child (e.g. plugin) automation, pass the child for \a.
56 * For region automation (e.g. MIDI CC), pass null for \a.
58 AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
59 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
60 PublicEditor& e, TimeAxisView& parent, bool show_regions,
61 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
63 TimeAxisView (s, e, &parent, canvas),
67 _controller(AutomationController::create(a, c->parameter(), c)),
69 _view (show_regions ? new AutomationStreamView(*this) : NULL),
71 clear_button (_("clear")),
72 auto_button (X_("")) /* force addition of a label */
74 if (!have_name_font) {
75 name_font = get_font_for_style (X_("AutomationTrackName"));
76 have_name_font = true;
84 mode_discrete_item = 0;
87 ignore_state_request = false;
88 first_call_to_set_height = true;
90 _base_rect = new SimpleRect(*_canvas_display);
91 _base_rect->property_x1() = 0.0;
92 _base_rect->property_y1() = 0.0;
93 _base_rect->property_x2() = LONG_MAX - 2;
94 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
96 /* outline ends and bottom */
97 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
98 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
100 _base_rect->set_data ("trackview", this);
102 _base_rect->signal_event().connect (bind (mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
105 _base_rect->lower_to_bottom();
107 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
109 auto_button.set_name ("TrackVisualButton");
110 clear_button.set_name ("TrackVisualButton");
111 hide_button.set_name ("TrackRemoveButton");
113 auto_button.unset_flags (Gtk::CAN_FOCUS);
114 clear_button.unset_flags (Gtk::CAN_FOCUS);
115 hide_button.unset_flags (Gtk::CAN_FOCUS);
117 controls_table.set_no_show_all();
119 ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state"));
120 ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track"));
121 ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("hide track"));
123 /* rearrange the name display */
125 /* we never show these for automation tracks, so make
126 life easier and remove them.
131 /* move the name label over a bit */
133 string shortpname = _name;
134 bool shortened = false;
137 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
139 if (shortpname != _name ){
143 name_label.set_text (shortpname);
144 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
146 if (nomparent.length()) {
148 /* limit the plug name string */
150 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
151 if (pname != nomparent) {
155 plugname = new Label (pname);
156 plugname->set_name (X_("TrackPlugName"));
158 name_label.set_name (X_("TrackParameterName"));
159 controls_table.remove (name_hbox);
160 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
161 plugname_packed = true;
162 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
165 plugname_packed = false;
169 string tipname = nomparent;
170 if (!tipname.empty()) {
174 ARDOUR_UI::instance()->tooltips().set_tip(controls_ebox, tipname);
177 /* add the buttons */
178 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
180 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
181 controls_table.attach (clear_button, 5, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
183 /* add bar controller */
184 controls_table.attach (*_controller.get(), 0, 8, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
186 controls_table.show_all ();
188 clear_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::clear_clicked));
189 hide_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
190 auto_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
192 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
193 controls_base_unselected_name = X_("AutomationTrackControlsBase");
194 controls_ebox.set_name (controls_base_unselected_name);
196 controls_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
198 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
199 _control->parameter());
202 set_state (*xml_node);
205 /* ask for notifications of any new RegionViews */
211 /* no regions, just a single line for the entire track (e.g. bus gain) */
214 boost::shared_ptr<AutomationLine> line(new AutomationLine (
215 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
220 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
221 line->queue_reset ();
225 /* make sure labels etc. are correct */
227 automation_state_changed ();
228 ColorsChanged.connect (mem_fun (*this, &AutomationTimeAxisView::color_handler));
231 AutomationTimeAxisView::~AutomationTimeAxisView ()
236 AutomationTimeAxisView::auto_clicked ()
238 using namespace Menu_Helpers;
240 if (automation_menu == 0) {
241 automation_menu = manage (new Menu);
242 automation_menu->set_name ("ArdourContextMenu");
243 MenuList& items (automation_menu->items());
245 items.push_back (MenuElem (_("Manual"), bind (mem_fun(*this,
246 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
247 items.push_back (MenuElem (_("Play"), bind (mem_fun(*this,
248 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
249 items.push_back (MenuElem (_("Write"), bind (mem_fun(*this,
250 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
251 items.push_back (MenuElem (_("Touch"), bind (mem_fun(*this,
252 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
255 automation_menu->popup (1, gtk_get_current_event_time());
259 AutomationTimeAxisView::set_automation_state (AutoState state)
261 if (!ignore_state_request) {
262 if (_route == _automatable) { // This is a time axis for route (not region) automation
263 _route->set_parameter_automation_state (_control->parameter(), state);
266 if (_control->list())
267 _control->alist()->set_automation_state(state);
270 _view->set_automation_state (state);
274 AutomationTimeAxisView::automation_state_changed ()
278 /* update button label */
283 state = _control->alist()->automation_state ();
286 switch (state & (Off|Play|Touch|Write)) {
288 auto_button.set_label (_("Manual"));
290 ignore_state_request = true;
291 auto_off_item->set_active (true);
292 auto_play_item->set_active (false);
293 auto_touch_item->set_active (false);
294 auto_write_item->set_active (false);
295 ignore_state_request = false;
299 auto_button.set_label (_("Play"));
300 if (auto_play_item) {
301 ignore_state_request = true;
302 auto_play_item->set_active (true);
303 auto_off_item->set_active (false);
304 auto_touch_item->set_active (false);
305 auto_write_item->set_active (false);
306 ignore_state_request = false;
310 auto_button.set_label (_("Write"));
311 if (auto_write_item) {
312 ignore_state_request = true;
313 auto_write_item->set_active (true);
314 auto_off_item->set_active (false);
315 auto_play_item->set_active (false);
316 auto_touch_item->set_active (false);
317 ignore_state_request = false;
321 auto_button.set_label (_("Touch"));
322 if (auto_touch_item) {
323 ignore_state_request = true;
324 auto_touch_item->set_active (true);
325 auto_off_item->set_active (false);
326 auto_play_item->set_active (false);
327 auto_write_item->set_active (false);
328 ignore_state_request = false;
332 auto_button.set_label (_("???"));
338 AutomationTimeAxisView::interpolation_changed ()
340 AutomationList::InterpolationStyle style = _control->list()->interpolation();
342 if (mode_line_item && mode_discrete_item) {
343 if (style == AutomationList::Discrete) {
344 mode_discrete_item->set_active(true);
345 mode_line_item->set_active(false);
347 mode_line_item->set_active(true);
348 mode_discrete_item->set_active(false);
353 _line->set_interpolation(style);
358 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
360 _control->list()->set_interpolation(style);
362 _line->set_interpolation(style);
367 AutomationTimeAxisView::clear_clicked ()
369 _session.begin_reversible_command (_("clear automation"));
373 _session.commit_reversible_command ();
377 AutomationTimeAxisView::set_height (uint32_t h)
379 bool changed = (height != (uint32_t) h) || first_call_to_set_height;
380 bool changed_between_small_and_normal = (
381 (height < hNormal && h >= hNormal) ||
382 (height >= hNormal ||
386 TimeAxisView* state_parent = get_parent_with_state ();
387 assert(state_parent);
388 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
390 TimeAxisView::set_height (h);
391 _base_rect->property_y2() = h;
394 _line->set_height(h);
397 _view->set_height(h);
398 _view->update_contents_height();
402 snprintf (buf, sizeof (buf), "%u", height);
404 xml_node->add_property ("height", buf);
407 if (changed_between_small_and_normal || first_call_to_set_height) {
409 first_call_to_set_height = false;
412 controls_table.remove (name_hbox);
415 if (plugname_packed) {
416 controls_table.remove (*plugname);
417 plugname_packed = false;
419 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
420 plugname_packed = true;
421 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
423 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
427 name_hbox.show_all ();
431 hide_button.show_all();
433 } else if (h >= hSmall) {
434 controls_table.remove (name_hbox);
436 if (plugname_packed) {
437 controls_table.remove (*plugname);
438 plugname_packed = false;
441 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
442 controls_table.hide_all ();
445 name_hbox.show_all ();
451 } else if (h >= hNormal){
452 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
456 /* only emit the signal if the height really changed */
457 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
462 AutomationTimeAxisView::set_samples_per_unit (double spu)
464 TimeAxisView::set_samples_per_unit (spu);
470 _view->set_samples_per_unit (spu);
474 AutomationTimeAxisView::hide_clicked ()
476 // LAME fix for refreshing the hide button
477 hide_button.set_sensitive(false);
479 set_marked_for_display (false);
482 hide_button.set_sensitive(true);
486 AutomationTimeAxisView::build_display_menu ()
488 using namespace Menu_Helpers;
490 /* get the size menu ready */
496 TimeAxisView::build_display_menu ();
498 /* now fill it with our stuff */
500 MenuList& items = display_menu->items();
502 items.push_back (MenuElem (_("Height"), *size_menu));
503 items.push_back (SeparatorElem());
504 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
505 items.push_back (SeparatorElem());
506 items.push_back (MenuElem (_("Clear"), mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
507 items.push_back (SeparatorElem());
511 Menu* auto_state_menu = manage (new Menu);
512 auto_state_menu->set_name ("ArdourContextMenu");
513 MenuList& as_items = auto_state_menu->items();
515 as_items.push_back (CheckMenuElem (_("Manual"),
516 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
517 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
519 as_items.push_back (CheckMenuElem (_("Play"),
520 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
521 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
523 as_items.push_back (CheckMenuElem (_("Write"),
524 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
525 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
527 as_items.push_back (CheckMenuElem (_("Touch"),
528 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
529 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
531 items.push_back (MenuElem (_("State"), *auto_state_menu));
535 if ( EventTypeMap::instance().is_midi_parameter(_control->parameter()) ) {
537 Menu* auto_mode_menu = manage (new Menu);
538 auto_mode_menu->set_name ("ArdourContextMenu");
539 MenuList& am_items = auto_mode_menu->items();
541 RadioMenuItem::Group group;
543 am_items.push_back (RadioMenuElem (group, _("Discrete"), bind (
544 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
545 AutomationList::Discrete)));
546 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
547 mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
549 // For discrete types we dont allow the linear option since it makes no sense for those Controls
550 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
551 am_items.push_back (RadioMenuElem (group, _("Line"), bind (
552 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
553 AutomationList::Linear)));
554 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
555 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
558 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
561 /* make sure the automation menu state is correct */
563 automation_state_changed ();
564 interpolation_changed ();
568 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
575 _canvas_display->w2i (x, y);
577 /* compute vertical fractional position */
579 y = 1.0 - (y / height);
583 _line->view_to_model_y (y);
585 _session.begin_reversible_command (_("add automation event"));
586 XMLNode& before = _control->alist()->get_state();
588 _control->alist()->add (when, y);
590 XMLNode& after = _control->alist()->get_state();
591 _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
593 _session.set_dirty ();
598 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
600 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
604 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
606 boost::shared_ptr<Evoral::ControlList> what_we_got;
607 boost::shared_ptr<AutomationList> alist (line.the_list());
610 XMLNode &before = alist->get_state();
614 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
615 _editor.get_cut_buffer().add (what_we_got);
616 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
621 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
622 _editor.get_cut_buffer().add (what_we_got);
627 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
628 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
635 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
636 double foo = (*x)->value;
637 line.model_to_view_y (foo);
646 AutomationTimeAxisView::reset_objects (PointSelection& selection)
648 reset_objects_one (*_line, selection);
652 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
654 boost::shared_ptr<AutomationList> alist(line.the_list());
656 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
658 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
660 if (&(*i).track != this) {
664 alist->reset_range ((*i).start, (*i).end);
669 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
671 return cut_copy_clear_objects_one (*_line, selection, op);
675 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
677 boost::shared_ptr<Evoral::ControlList> what_we_got;
678 boost::shared_ptr<AutomationList> alist(line.the_list());
681 XMLNode &before = alist->get_state();
683 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
685 if (&(*i).track != this) {
691 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
692 _editor.get_cut_buffer().add (what_we_got);
693 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
698 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
699 _editor.get_cut_buffer().add (what_we_got);
704 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
705 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
715 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
716 double foo = (*x)->value;
717 line.model_to_view_y (foo);
726 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
728 return paste_one (*_line, pos, times, selection, nth);
732 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
734 AutomationSelection::iterator p;
735 boost::shared_ptr<AutomationList> alist(line.the_list());
737 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
739 if (p == selection.lines.end()) {
743 /* Make a copy of the list because we have to scale the
744 values from view coordinates to model coordinates, and we're
745 not supposed to modify the points in the selection.
748 AutomationList copy (**p);
750 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
751 double foo = (*x)->value;
752 line.view_to_model_y (foo);
756 XMLNode &before = alist->get_state();
757 alist->paste (copy, pos, times);
758 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
764 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
766 if (_line && touched (top, bot)) {
770 /* remember: this is X Window - coordinate space starts in upper left and moves down.
771 _y_position is the "origin" or "top" of the track.
774 double mybot = _y_position + height;
776 if (_y_position >= top && mybot <= bot) {
778 /* _y_position is below top, mybot is above bot, so we're fully
787 /* top and bot are within _y_position .. mybot */
789 topfrac = 1.0 - ((top - _y_position) / height);
790 botfrac = 1.0 - ((bot - _y_position) / height);
794 _line->get_selectables (start, end, botfrac, topfrac, results);
799 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
802 _line->get_inverted_selectables (sel, result);
806 AutomationTimeAxisView::set_selected_points (PointSelection& points)
809 _line->set_selected_points (points);
813 AutomationTimeAxisView::clear_lines ()
816 automation_connection.disconnect ();
820 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
824 assert(line->the_list() == _control->list());
826 automation_connection = _control->alist()->automation_state_changed.connect
827 (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
830 //_controller = AutomationController::create(_session, line->the_list(), _control);
832 line->set_height (height);
834 /* pick up the current state */
835 automation_state_changed ();
841 AutomationTimeAxisView::entered()
844 _line->track_entered();
848 AutomationTimeAxisView::exited ()
851 _line->track_exited();
855 AutomationTimeAxisView::set_colors ()
857 for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
866 AutomationTimeAxisView::color_handler ()
874 AutomationTimeAxisView::set_state (const XMLNode& node)
876 TimeAxisView::set_state (node);
878 XMLProperty const * type = node.property ("automation-id");
879 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
880 XMLProperty const * shown = node.property ("shown");
881 if (shown && shown->value () == "yes") {
882 set_marked_for_display (true);
883 _canvas_display->show (); /* FIXME: necessary? show_at? */
887 if (!_marked_for_display) {
895 AutomationTimeAxisView::get_state_node ()
897 TimeAxisView* state_parent = get_parent_with_state ();
900 return state_parent->get_automation_child_xml_node (_control->parameter());
907 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
909 XMLNode* xml_node = get_state_node();
911 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
916 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
918 update_extra_xml_shown (true);
920 return TimeAxisView::show_at (y, nth, parent);
924 AutomationTimeAxisView::hide ()
926 update_extra_xml_shown (false);
928 TimeAxisView::hide ();