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";
52 /** \a a the automatable object this time axis is to display data for.
53 * For route/track automation (e.g. gain) pass the route for both \r and \a.
54 * For route child (e.g. plugin) automation, pass the child for \a.
55 * For region automation (e.g. MIDI CC), pass null for \a.
57 AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
58 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
59 PublicEditor& e, TimeAxisView& parent, bool show_regions,
60 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
62 TimeAxisView (s, e, &parent, canvas),
66 _controller(AutomationController::create(a, c->parameter(), c)),
68 _view (show_regions ? new AutomationStreamView(*this) : NULL),
70 clear_button (_("clear")),
71 auto_button (X_("")) /* force addition of a label */
73 if (!have_name_font) {
74 name_font = get_font_for_style (X_("AutomationTrackName"));
75 have_name_font = true;
83 mode_discrete_item = 0;
86 ignore_state_request = false;
87 first_call_to_set_height = true;
89 _base_rect = new SimpleRect(*canvas_display);
90 _base_rect->property_x1() = 0.0;
91 _base_rect->property_y1() = 0.0;
92 _base_rect->property_x2() = LONG_MAX - 2;
93 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
95 /* outline ends and bottom */
96 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
97 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
99 _base_rect->set_data ("trackview", this);
101 _base_rect->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_automation_track_event),
104 _base_rect->lower_to_bottom();
106 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
108 auto_button.set_name ("TrackVisualButton");
109 clear_button.set_name ("TrackVisualButton");
110 hide_button.set_name ("TrackRemoveButton");
112 auto_button.unset_flags (Gtk::CAN_FOCUS);
113 clear_button.unset_flags (Gtk::CAN_FOCUS);
114 hide_button.unset_flags (Gtk::CAN_FOCUS);
116 controls_table.set_no_show_all();
118 ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state"));
119 ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track"));
120 ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("hide track"));
122 /* rearrange the name display */
124 /* we never show these for automation tracks, so make
125 life easier and remove them.
130 /* move the name label over a bit */
132 string shortpname = _name;
133 bool shortened = false;
136 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
138 if (shortpname != _name ){
142 name_label.set_text (shortpname);
143 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
145 if (nomparent.length()) {
147 /* limit the plug name string */
149 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
150 if (pname != nomparent) {
154 plugname = new Label (pname);
155 plugname->set_name (X_("TrackPlugName"));
157 name_label.set_name (X_("TrackParameterName"));
158 controls_table.remove (name_hbox);
159 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
160 plugname_packed = true;
161 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
164 plugname_packed = false;
168 string tipname = nomparent;
169 if (!tipname.empty()) {
173 ARDOUR_UI::instance()->tooltips().set_tip(controls_ebox, tipname);
176 /* add the buttons */
177 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
179 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
180 controls_table.attach (clear_button, 5, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
182 /* add bar controller */
183 controls_table.attach (*_controller.get(), 0, 8, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
185 controls_table.show_all ();
187 clear_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::clear_clicked));
188 hide_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
189 auto_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
191 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
192 controls_base_unselected_name = X_("AutomationTrackControlsBase");
193 controls_ebox.set_name (controls_base_unselected_name);
195 controls_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
197 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
198 _control->parameter());
201 set_state (*xml_node);
204 /* ask for notifications of any new RegionViews */
210 /* no regions, just a single line for the entire track (e.g. bus gain) */
213 boost::shared_ptr<AutomationLine> line(new AutomationLine (
214 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
219 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
220 line->queue_reset ();
224 /* make sure labels etc. are correct */
226 automation_state_changed ();
227 ColorsChanged.connect (mem_fun (*this, &AutomationTimeAxisView::color_handler));
230 AutomationTimeAxisView::~AutomationTimeAxisView ()
235 AutomationTimeAxisView::auto_clicked ()
237 using namespace Menu_Helpers;
239 if (automation_menu == 0) {
240 automation_menu = manage (new Menu);
241 automation_menu->set_name ("ArdourContextMenu");
242 MenuList& items (automation_menu->items());
244 items.push_back (MenuElem (_("Manual"), bind (mem_fun(*this,
245 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
246 items.push_back (MenuElem (_("Play"), bind (mem_fun(*this,
247 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
248 items.push_back (MenuElem (_("Write"), bind (mem_fun(*this,
249 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
250 items.push_back (MenuElem (_("Touch"), bind (mem_fun(*this,
251 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
254 automation_menu->popup (1, gtk_get_current_event_time());
258 AutomationTimeAxisView::set_automation_state (AutoState state)
260 if (!ignore_state_request) {
261 if (_route == _automatable) { // This is a time axis for route (not region) automation
262 _route->set_parameter_automation_state (_control->parameter(), state);
265 if (_control->list())
266 _control->alist()->set_automation_state(state);
269 _view->set_automation_state (state);
273 AutomationTimeAxisView::automation_state_changed ()
277 /* update button label */
282 state = _control->alist()->automation_state ();
285 switch (state & (Off|Play|Touch|Write)) {
287 auto_button.set_label (_("Manual"));
289 ignore_state_request = true;
290 auto_off_item->set_active (true);
291 auto_play_item->set_active (false);
292 auto_touch_item->set_active (false);
293 auto_write_item->set_active (false);
294 ignore_state_request = false;
298 auto_button.set_label (_("Play"));
299 if (auto_play_item) {
300 ignore_state_request = true;
301 auto_play_item->set_active (true);
302 auto_off_item->set_active (false);
303 auto_touch_item->set_active (false);
304 auto_write_item->set_active (false);
305 ignore_state_request = false;
309 auto_button.set_label (_("Write"));
310 if (auto_write_item) {
311 ignore_state_request = true;
312 auto_write_item->set_active (true);
313 auto_off_item->set_active (false);
314 auto_play_item->set_active (false);
315 auto_touch_item->set_active (false);
316 ignore_state_request = false;
320 auto_button.set_label (_("Touch"));
321 if (auto_touch_item) {
322 ignore_state_request = true;
323 auto_touch_item->set_active (true);
324 auto_off_item->set_active (false);
325 auto_play_item->set_active (false);
326 auto_write_item->set_active (false);
327 ignore_state_request = false;
331 auto_button.set_label (_("???"));
337 AutomationTimeAxisView::interpolation_changed ()
339 AutomationList::InterpolationStyle style = _control->list()->interpolation();
341 if (mode_line_item && mode_discrete_item) {
342 if (style == AutomationList::Discrete) {
343 mode_discrete_item->set_active(true);
344 mode_line_item->set_active(false);
346 mode_line_item->set_active(true);
347 mode_discrete_item->set_active(false);
352 _line->set_interpolation(style);
356 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
358 _control->list()->set_interpolation(style);
360 _line->set_interpolation(style);
364 AutomationTimeAxisView::clear_clicked ()
366 _session.begin_reversible_command (_("clear automation"));
369 _session.commit_reversible_command ();
373 AutomationTimeAxisView::set_height (uint32_t h)
375 bool changed = (height != (uint32_t) h) || first_call_to_set_height;
376 bool changed_between_small_and_normal = ( (height < hNormal && h >= hNormal) || (height >= hNormal || h < hNormal) );
378 TimeAxisView* state_parent = get_parent_with_state ();
379 assert(state_parent);
380 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
382 TimeAxisView::set_height (h);
383 _base_rect->property_y2() = h;
386 _line->set_height(h);
389 _view->set_height(h);
390 _view->update_contents_height();
394 snprintf (buf, sizeof (buf), "%u", height);
396 xml_node->add_property ("height", buf);
399 if (changed_between_small_and_normal || first_call_to_set_height) {
401 first_call_to_set_height = false;
404 controls_table.remove (name_hbox);
407 if (plugname_packed) {
408 controls_table.remove (*plugname);
409 plugname_packed = false;
411 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
412 plugname_packed = true;
413 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
415 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
419 name_hbox.show_all ();
423 hide_button.show_all();
425 } else if (h >= hSmall) {
426 controls_table.remove (name_hbox);
428 if (plugname_packed) {
429 controls_table.remove (*plugname);
430 plugname_packed = false;
433 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
434 controls_table.hide_all ();
437 name_hbox.show_all ();
443 } else if (h >= hNormal){
444 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
448 /* only emit the signal if the height really changed */
449 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
454 AutomationTimeAxisView::set_samples_per_unit (double spu)
456 TimeAxisView::set_samples_per_unit (spu);
462 _view->set_samples_per_unit (spu);
466 AutomationTimeAxisView::hide_clicked ()
468 // LAME fix for refreshing the hide button
469 hide_button.set_sensitive(false);
471 set_marked_for_display (false);
474 hide_button.set_sensitive(true);
478 AutomationTimeAxisView::build_display_menu ()
480 using namespace Menu_Helpers;
482 /* get the size menu ready */
488 TimeAxisView::build_display_menu ();
490 /* now fill it with our stuff */
492 MenuList& items = display_menu->items();
494 items.push_back (MenuElem (_("Height"), *size_menu));
495 items.push_back (SeparatorElem());
496 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
497 items.push_back (SeparatorElem());
498 items.push_back (MenuElem (_("Clear"), mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
499 items.push_back (SeparatorElem());
503 Menu* auto_state_menu = manage (new Menu);
504 auto_state_menu->set_name ("ArdourContextMenu");
505 MenuList& as_items = auto_state_menu->items();
507 as_items.push_back (CheckMenuElem (_("Manual"),
508 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
509 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
511 as_items.push_back (CheckMenuElem (_("Play"),
512 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
513 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
515 as_items.push_back (CheckMenuElem (_("Write"),
516 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
517 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
519 as_items.push_back (CheckMenuElem (_("Touch"),
520 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
521 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
523 items.push_back (MenuElem (_("State"), *auto_state_menu));
527 if (_control->parameter().type() == MidiCCAutomation) {
528 Menu* auto_mode_menu = manage (new Menu);
529 auto_mode_menu->set_name ("ArdourContextMenu");
530 MenuList& am_items = auto_mode_menu->items();
532 RadioMenuItem::Group group;
534 am_items.push_back (RadioMenuElem (group, _("Discrete"), bind (
535 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
536 AutomationList::Discrete)));
537 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
538 //mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
540 am_items.push_back (RadioMenuElem (group, _("Line"), bind (
541 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
542 AutomationList::Linear)));
543 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
544 //mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
546 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
549 /* make sure the automation menu state is correct */
551 automation_state_changed ();
552 interpolation_changed ();
556 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
563 canvas_display->w2i (x, y);
565 /* compute vertical fractional position */
567 y = 1.0 - (y / height);
571 _line->view_to_model_y (y);
573 _session.begin_reversible_command (_("add automation event"));
574 XMLNode& before = _control->alist()->get_state();
576 _control->alist()->add (when, y);
578 XMLNode& after = _control->alist()->get_state();
579 _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
581 _session.set_dirty ();
586 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
588 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
592 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
594 boost::shared_ptr<Evoral::ControlList> what_we_got;
595 boost::shared_ptr<AutomationList> alist (line.the_list());
598 XMLNode &before = alist->get_state();
602 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
603 editor.get_cut_buffer().add (what_we_got);
604 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
609 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
610 editor.get_cut_buffer().add (what_we_got);
615 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
616 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
623 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
624 double foo = (*x)->value;
625 line.model_to_view_y (foo);
634 AutomationTimeAxisView::reset_objects (PointSelection& selection)
636 reset_objects_one (*_line, selection);
640 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
642 boost::shared_ptr<AutomationList> alist(line.the_list());
644 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
646 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
648 if (&(*i).track != this) {
652 alist->reset_range ((*i).start, (*i).end);
657 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
659 return cut_copy_clear_objects_one (*_line, selection, op);
663 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
665 boost::shared_ptr<Evoral::ControlList> what_we_got;
666 boost::shared_ptr<AutomationList> alist(line.the_list());
669 XMLNode &before = alist->get_state();
671 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
673 if (&(*i).track != this) {
679 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
680 editor.get_cut_buffer().add (what_we_got);
681 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
686 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
687 editor.get_cut_buffer().add (what_we_got);
692 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
693 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
703 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
704 double foo = (*x)->value;
705 line.model_to_view_y (foo);
714 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
716 return paste_one (*_line, pos, times, selection, nth);
720 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
722 AutomationSelection::iterator p;
723 boost::shared_ptr<AutomationList> alist(line.the_list());
725 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
727 if (p == selection.lines.end()) {
731 /* Make a copy of the list because we have to scale the
732 values from view coordinates to model coordinates, and we're
733 not supposed to modify the points in the selection.
736 AutomationList copy (**p);
738 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
739 double foo = (*x)->value;
740 line.view_to_model_y (foo);
744 XMLNode &before = alist->get_state();
745 alist->paste (copy, pos, times);
746 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
752 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
754 if (_line && touched (top, bot)) {
758 /* remember: this is X Window - coordinate space starts in upper left and moves down.
759 y_position is the "origin" or "top" of the track.
762 double mybot = y_position + height;
764 if (y_position >= top && mybot <= bot) {
766 /* y_position is below top, mybot is above bot, so we're fully
775 /* top and bot are within y_position .. mybot */
777 topfrac = 1.0 - ((top - y_position) / height);
778 botfrac = 1.0 - ((bot - y_position) / height);
782 _line->get_selectables (start, end, botfrac, topfrac, results);
787 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
790 _line->get_inverted_selectables (sel, result);
794 AutomationTimeAxisView::set_selected_points (PointSelection& points)
797 _line->set_selected_points (points);
801 AutomationTimeAxisView::clear_lines ()
804 automation_connection.disconnect ();
808 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
812 assert(line->the_list() == _control->list());
814 automation_connection = _control->alist()->automation_state_changed.connect
815 (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
818 //_controller = AutomationController::create(_session, line->the_list(), _control);
820 line->set_height (height);
822 /* pick up the current state */
823 automation_state_changed ();
829 AutomationTimeAxisView::entered()
832 _line->track_entered();
836 AutomationTimeAxisView::exited ()
839 _line->track_exited();
843 AutomationTimeAxisView::set_colors ()
845 for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
854 AutomationTimeAxisView::color_handler ()
862 AutomationTimeAxisView::set_state (const XMLNode& node)
864 TimeAxisView::set_state (node);
867 XMLNodeConstIterator iter;
869 kids = node.children ();
871 for (iter = kids.begin(); iter != kids.end(); ++iter) {
873 if ((*iter)->name() == state_node_name) {
874 XMLProperty* type = (*iter)->property("automation-id");
876 if (type && type->value() == ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter())) {
877 XMLProperty *shown = (*iter)->property("shown-editor");
879 if (shown && shown->value() == "yes") {
880 set_marked_for_display(true);
881 canvas_display->show(); /* FIXME: necessary? show_at? */
888 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 ();