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>
27 #include "ardour_ui.h"
28 #include "automation_time_axis.h"
29 #include "automation_streamview.h"
30 #include "route_time_axis.h"
31 #include "automation_line.h"
32 #include "public_editor.h"
33 #include "simplerect.h"
34 #include "selection.h"
35 #include "rgb_macros.h"
36 #include "automation_selectable.h"
37 #include "point_selection.h"
38 #include "canvas_impl.h"
43 using namespace ARDOUR;
46 using namespace Gtkmm2ext;
47 using namespace Editing;
49 Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
50 bool AutomationTimeAxisView::have_name_font = false;
51 const string AutomationTimeAxisView::state_node_name = "AutomationChild";
54 /** \a a the automatable object this time axis is to display data for.
55 * For route/track automation (e.g. gain) pass the route for both \r and \a.
56 * For route child (e.g. plugin) automation, pass the child for \a.
57 * For region automation (e.g. MIDI CC), pass null for \a.
59 AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
60 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
61 PublicEditor& e, TimeAxisView& parent, bool show_regions,
62 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
64 TimeAxisView (s, e, &parent, canvas),
68 _controller(AutomationController::create(a, c->parameter(), c)),
70 _view (show_regions ? new AutomationStreamView(*this) : NULL),
72 clear_button (_("clear")),
73 auto_button (X_("")) /* force addition of a label */
75 if (!have_name_font) {
76 name_font = get_font_for_style (X_("AutomationTrackName"));
77 have_name_font = true;
85 mode_discrete_item = 0;
88 ignore_state_request = false;
89 first_call_to_set_height = true;
91 _base_rect = new SimpleRect(*_canvas_display);
92 _base_rect->property_x1() = 0.0;
93 _base_rect->property_y1() = 0.0;
94 _base_rect->property_x2() = LONG_MAX - 2;
95 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
97 /* outline ends and bottom */
98 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
99 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
101 _base_rect->set_data ("trackview", this);
103 _base_rect->signal_event().connect (bind (mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
106 _base_rect->lower_to_bottom();
108 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
110 auto_button.set_name ("TrackVisualButton");
111 clear_button.set_name ("TrackVisualButton");
112 hide_button.set_name ("TrackRemoveButton");
114 auto_button.unset_flags (Gtk::CAN_FOCUS);
115 clear_button.unset_flags (Gtk::CAN_FOCUS);
116 hide_button.unset_flags (Gtk::CAN_FOCUS);
118 controls_table.set_no_show_all();
120 ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state"));
121 ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track"));
122 ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("hide track"));
124 /* rearrange the name display */
126 /* we never show these for automation tracks, so make
127 life easier and remove them.
132 /* move the name label over a bit */
134 string shortpname = _name;
135 bool shortened = false;
138 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
140 if (shortpname != _name ){
144 name_label.set_text (shortpname);
145 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
147 if (nomparent.length()) {
149 /* limit the plug name string */
151 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
152 if (pname != nomparent) {
156 plugname = new Label (pname);
157 plugname->set_name (X_("TrackPlugName"));
159 name_label.set_name (X_("TrackParameterName"));
160 controls_table.remove (name_hbox);
161 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
162 plugname_packed = true;
163 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
166 plugname_packed = false;
170 string tipname = nomparent;
171 if (!tipname.empty()) {
175 ARDOUR_UI::instance()->tooltips().set_tip(controls_ebox, tipname);
178 /* add the buttons */
179 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
181 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
182 controls_table.attach (clear_button, 5, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
184 /* add bar controller */
185 controls_table.attach (*_controller.get(), 0, 8, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
187 controls_table.show_all ();
189 clear_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::clear_clicked));
190 hide_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
191 auto_button.signal_clicked().connect (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 controls_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
199 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
200 _control->parameter());
203 set_state (*xml_node);
206 /* ask for notifications of any new RegionViews */
212 /* no regions, just a single line for the entire track (e.g. bus gain) */
215 boost::shared_ptr<AutomationLine> line(new AutomationLine (
216 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
221 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
222 line->queue_reset ();
226 /* make sure labels etc. are correct */
228 automation_state_changed ();
229 ColorsChanged.connect (mem_fun (*this, &AutomationTimeAxisView::color_handler));
232 AutomationTimeAxisView::~AutomationTimeAxisView ()
237 AutomationTimeAxisView::auto_clicked ()
239 using namespace Menu_Helpers;
241 if (automation_menu == 0) {
242 automation_menu = manage (new Menu);
243 automation_menu->set_name ("ArdourContextMenu");
244 MenuList& items (automation_menu->items());
246 items.push_back (MenuElem (_("Manual"), bind (mem_fun(*this,
247 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
248 items.push_back (MenuElem (_("Play"), bind (mem_fun(*this,
249 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
250 items.push_back (MenuElem (_("Write"), bind (mem_fun(*this,
251 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
252 items.push_back (MenuElem (_("Touch"), bind (mem_fun(*this,
253 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
256 automation_menu->popup (1, gtk_get_current_event_time());
260 AutomationTimeAxisView::set_automation_state (AutoState state)
262 if (!ignore_state_request) {
263 if (_route == _automatable) { // This is a time axis for route (not region) automation
264 _route->set_parameter_automation_state (_control->parameter(), state);
267 if (_control->list())
268 _control->alist()->set_automation_state(state);
271 _view->set_automation_state (state);
275 AutomationTimeAxisView::automation_state_changed ()
279 /* update button label */
284 state = _control->alist()->automation_state ();
287 switch (state & (Off|Play|Touch|Write)) {
289 auto_button.set_label (_("Manual"));
291 ignore_state_request = true;
292 auto_off_item->set_active (true);
293 auto_play_item->set_active (false);
294 auto_touch_item->set_active (false);
295 auto_write_item->set_active (false);
296 ignore_state_request = false;
300 auto_button.set_label (_("Play"));
301 if (auto_play_item) {
302 ignore_state_request = true;
303 auto_play_item->set_active (true);
304 auto_off_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 (_("Write"));
312 if (auto_write_item) {
313 ignore_state_request = true;
314 auto_write_item->set_active (true);
315 auto_off_item->set_active (false);
316 auto_play_item->set_active (false);
317 auto_touch_item->set_active (false);
318 ignore_state_request = false;
322 auto_button.set_label (_("Touch"));
323 if (auto_touch_item) {
324 ignore_state_request = true;
325 auto_touch_item->set_active (true);
326 auto_off_item->set_active (false);
327 auto_play_item->set_active (false);
328 auto_write_item->set_active (false);
329 ignore_state_request = false;
333 auto_button.set_label (_("???"));
339 AutomationTimeAxisView::interpolation_changed ()
341 AutomationList::InterpolationStyle style = _control->list()->interpolation();
343 if (mode_line_item && mode_discrete_item) {
344 if (style == AutomationList::Discrete) {
345 mode_discrete_item->set_active(true);
346 mode_line_item->set_active(false);
348 mode_line_item->set_active(true);
349 mode_discrete_item->set_active(false);
354 _line->set_interpolation(style);
359 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
361 _control->list()->set_interpolation(style);
363 _line->set_interpolation(style);
368 AutomationTimeAxisView::clear_clicked ()
370 _session.begin_reversible_command (_("clear automation"));
374 _session.commit_reversible_command ();
378 AutomationTimeAxisView::set_height (uint32_t h)
380 bool changed = (height != (uint32_t) h) || first_call_to_set_height;
381 bool changed_between_small_and_normal = (
382 (height < hNormal && h >= hNormal) ||
383 (height >= hNormal ||
387 TimeAxisView* state_parent = get_parent_with_state ();
388 assert(state_parent);
389 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
391 TimeAxisView::set_height (h);
392 _base_rect->property_y2() = h;
395 _line->set_height(h);
398 _view->set_height(h);
399 _view->update_contents_height();
403 snprintf (buf, sizeof (buf), "%u", height);
405 xml_node->add_property ("height", buf);
408 if (changed_between_small_and_normal || first_call_to_set_height) {
410 first_call_to_set_height = false;
413 controls_table.remove (name_hbox);
416 if (plugname_packed) {
417 controls_table.remove (*plugname);
418 plugname_packed = false;
420 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
421 plugname_packed = true;
422 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
424 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
428 name_hbox.show_all ();
432 hide_button.show_all();
434 } else if (h >= hSmall) {
435 controls_table.remove (name_hbox);
437 if (plugname_packed) {
438 controls_table.remove (*plugname);
439 plugname_packed = false;
442 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
443 controls_table.hide_all ();
446 name_hbox.show_all ();
452 } else if (h >= hNormal){
453 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
457 /* only emit the signal if the height really changed */
458 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
463 AutomationTimeAxisView::set_samples_per_unit (double spu)
465 TimeAxisView::set_samples_per_unit (spu);
471 _view->set_samples_per_unit (spu);
475 AutomationTimeAxisView::hide_clicked ()
477 // LAME fix for refreshing the hide button
478 hide_button.set_sensitive(false);
480 set_marked_for_display (false);
483 hide_button.set_sensitive(true);
487 AutomationTimeAxisView::build_display_menu ()
489 using namespace Menu_Helpers;
491 /* get the size menu ready */
497 TimeAxisView::build_display_menu ();
499 /* now fill it with our stuff */
501 MenuList& items = display_menu->items();
503 items.push_back (MenuElem (_("Height"), *size_menu));
504 items.push_back (SeparatorElem());
505 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
506 items.push_back (SeparatorElem());
507 items.push_back (MenuElem (_("Clear"), mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
508 items.push_back (SeparatorElem());
512 Menu* auto_state_menu = manage (new Menu);
513 auto_state_menu->set_name ("ArdourContextMenu");
514 MenuList& as_items = auto_state_menu->items();
516 as_items.push_back (CheckMenuElem (_("Manual"),
517 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
518 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
520 as_items.push_back (CheckMenuElem (_("Play"),
521 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
522 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
524 as_items.push_back (CheckMenuElem (_("Write"),
525 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
526 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
528 as_items.push_back (CheckMenuElem (_("Touch"),
529 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
530 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
532 items.push_back (MenuElem (_("State"), *auto_state_menu));
536 if ( EventTypeMap::instance().is_midi_parameter(_control->parameter()) ) {
538 Menu* auto_mode_menu = manage (new Menu);
539 auto_mode_menu->set_name ("ArdourContextMenu");
540 MenuList& am_items = auto_mode_menu->items();
542 RadioMenuItem::Group group;
544 am_items.push_back (RadioMenuElem (group, _("Discrete"), bind (
545 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
546 AutomationList::Discrete)));
547 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
548 mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
550 // For discrete types we dont allow the linear option since it makes no sense for those Controls
551 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
552 am_items.push_back (RadioMenuElem (group, _("Line"), bind (
553 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
554 AutomationList::Linear)));
555 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
556 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
559 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
562 /* make sure the automation menu state is correct */
564 automation_state_changed ();
565 interpolation_changed ();
569 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
576 _canvas_display->w2i (x, y);
578 /* compute vertical fractional position */
580 y = 1.0 - (y / height);
584 _line->view_to_model_y (y);
586 _session.begin_reversible_command (_("add automation event"));
587 XMLNode& before = _control->alist()->get_state();
589 _control->alist()->add (when, y);
591 XMLNode& after = _control->alist()->get_state();
592 _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
594 _session.set_dirty ();
599 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
601 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
605 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
607 boost::shared_ptr<Evoral::ControlList> what_we_got;
608 boost::shared_ptr<AutomationList> alist (line.the_list());
611 XMLNode &before = alist->get_state();
615 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
616 _editor.get_cut_buffer().add (what_we_got);
617 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
622 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
623 _editor.get_cut_buffer().add (what_we_got);
628 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
629 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
636 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
637 double foo = (*x)->value;
638 line.model_to_view_y (foo);
647 AutomationTimeAxisView::reset_objects (PointSelection& selection)
649 reset_objects_one (*_line, selection);
653 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
655 boost::shared_ptr<AutomationList> alist(line.the_list());
657 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
659 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
661 if (&(*i).track != this) {
665 alist->reset_range ((*i).start, (*i).end);
670 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
672 return cut_copy_clear_objects_one (*_line, selection, op);
676 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
678 boost::shared_ptr<Evoral::ControlList> what_we_got;
679 boost::shared_ptr<AutomationList> alist(line.the_list());
682 XMLNode &before = alist->get_state();
684 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
686 if (&(*i).track != this) {
692 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
693 _editor.get_cut_buffer().add (what_we_got);
694 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
699 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
700 _editor.get_cut_buffer().add (what_we_got);
705 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
706 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
716 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
717 double foo = (*x)->value;
718 line.model_to_view_y (foo);
727 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
729 return paste_one (*_line, pos, times, selection, nth);
733 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
735 AutomationSelection::iterator p;
736 boost::shared_ptr<AutomationList> alist(line.the_list());
738 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
740 if (p == selection.lines.end()) {
744 /* Make a copy of the list because we have to scale the
745 values from view coordinates to model coordinates, and we're
746 not supposed to modify the points in the selection.
749 AutomationList copy (**p);
751 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
752 double foo = (*x)->value;
753 line.view_to_model_y (foo);
757 XMLNode &before = alist->get_state();
758 alist->paste (copy, pos, times);
759 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
765 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
767 if (_line && touched (top, bot)) {
771 /* remember: this is X Window - coordinate space starts in upper left and moves down.
772 _y_position is the "origin" or "top" of the track.
775 double mybot = _y_position + height;
777 if (_y_position >= top && mybot <= bot) {
779 /* _y_position is below top, mybot is above bot, so we're fully
788 /* top and bot are within _y_position .. mybot */
790 topfrac = 1.0 - ((top - _y_position) / height);
791 botfrac = 1.0 - ((bot - _y_position) / height);
795 _line->get_selectables (start, end, botfrac, topfrac, results);
800 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
803 _line->get_inverted_selectables (sel, result);
807 AutomationTimeAxisView::set_selected_points (PointSelection& points)
810 _line->set_selected_points (points);
814 AutomationTimeAxisView::clear_lines ()
817 automation_connection.disconnect ();
821 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
825 assert(line->the_list() == _control->list());
827 automation_connection = _control->alist()->automation_state_changed.connect
828 (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
831 //_controller = AutomationController::create(_session, line->the_list(), _control);
833 line->set_height (height);
835 /* pick up the current state */
836 automation_state_changed ();
842 AutomationTimeAxisView::entered()
845 _line->track_entered();
849 AutomationTimeAxisView::exited ()
852 _line->track_exited();
856 AutomationTimeAxisView::set_colors ()
858 for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
867 AutomationTimeAxisView::color_handler ()
875 AutomationTimeAxisView::set_state (const XMLNode& node)
877 TimeAxisView::set_state (node);
879 XMLProperty const * type = node.property ("automation-id");
880 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
881 XMLProperty const * shown = node.property ("shown");
882 if (shown && shown->value () == "yes") {
883 set_marked_for_display (true);
884 _canvas_display->show (); /* FIXME: necessary? show_at? */
888 if (!_marked_for_display) {
896 AutomationTimeAxisView::get_state_node ()
898 TimeAxisView* state_parent = get_parent_with_state ();
901 return state_parent->get_automation_child_xml_node (_control->parameter());
908 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
910 XMLNode* xml_node = get_state_node();
912 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
917 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
919 update_extra_xml_shown (true);
921 return TimeAxisView::show_at (y, nth, parent);
925 AutomationTimeAxisView::hide ()
927 update_extra_xml_shown (false);
929 TimeAxisView::hide ();