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);
279 AutomationTimeAxisView::automation_state_changed ()
283 /* update button label */
288 state = _control->alist()->automation_state ();
291 switch (state & (Off|Play|Touch|Write)) {
293 auto_button.set_label (_("Manual"));
295 ignore_state_request = true;
296 auto_off_item->set_active (true);
297 auto_play_item->set_active (false);
298 auto_touch_item->set_active (false);
299 auto_write_item->set_active (false);
300 ignore_state_request = false;
304 auto_button.set_label (_("Play"));
305 if (auto_play_item) {
306 ignore_state_request = true;
307 auto_play_item->set_active (true);
308 auto_off_item->set_active (false);
309 auto_touch_item->set_active (false);
310 auto_write_item->set_active (false);
311 ignore_state_request = false;
315 auto_button.set_label (_("Write"));
316 if (auto_write_item) {
317 ignore_state_request = true;
318 auto_write_item->set_active (true);
319 auto_off_item->set_active (false);
320 auto_play_item->set_active (false);
321 auto_touch_item->set_active (false);
322 ignore_state_request = false;
326 auto_button.set_label (_("Touch"));
327 if (auto_touch_item) {
328 ignore_state_request = true;
329 auto_touch_item->set_active (true);
330 auto_off_item->set_active (false);
331 auto_play_item->set_active (false);
332 auto_write_item->set_active (false);
333 ignore_state_request = false;
337 auto_button.set_label (_("???"));
343 AutomationTimeAxisView::interpolation_changed ()
345 AutomationList::InterpolationStyle style = _control->list()->interpolation();
347 if (mode_line_item && mode_discrete_item) {
348 if (style == AutomationList::Discrete) {
349 mode_discrete_item->set_active(true);
350 mode_line_item->set_active(false);
352 mode_line_item->set_active(true);
353 mode_discrete_item->set_active(false);
358 _line->set_interpolation(style);
363 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
365 _control->list()->set_interpolation(style);
367 _line->set_interpolation(style);
372 AutomationTimeAxisView::clear_clicked ()
374 _session->begin_reversible_command (_("clear automation"));
378 _session->commit_reversible_command ();
382 AutomationTimeAxisView::set_height (uint32_t h)
384 bool changed = (height != (uint32_t) h) || first_call_to_set_height;
385 bool changed_between_small_and_normal = (
386 (height < hNormal && h >= hNormal)
387 || (height >= hNormal || h < hNormal) );
389 TimeAxisView* state_parent = get_parent_with_state ();
390 assert(state_parent);
391 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
393 TimeAxisView::set_height (h);
394 _base_rect->property_y2() = h;
397 _line->set_height(h);
400 _view->set_height(h);
401 _view->update_contents_height();
405 snprintf (buf, sizeof (buf), "%u", height);
407 xml_node->add_property ("height", buf);
410 if (changed_between_small_and_normal || first_call_to_set_height) {
412 first_call_to_set_height = false;
415 controls_table.remove (name_hbox);
418 if (plugname_packed) {
419 controls_table.remove (*plugname);
420 plugname_packed = false;
422 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
423 plugname_packed = true;
424 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
426 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
430 name_hbox.show_all ();
433 hide_button.show_all();
435 } else if (h >= hSmall) {
436 controls_table.remove (name_hbox);
438 if (plugname_packed) {
439 controls_table.remove (*plugname);
440 plugname_packed = false;
443 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
444 controls_table.hide_all ();
447 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 if (canvas_item_visible (_canvas_display)) {
458 /* only emit the signal if the height really changed and we were visible */
459 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
465 AutomationTimeAxisView::set_samples_per_unit (double spu)
467 TimeAxisView::set_samples_per_unit (spu);
473 _view->set_samples_per_unit (spu);
477 AutomationTimeAxisView::hide_clicked ()
479 // LAME fix for refreshing the hide button
480 hide_button.set_sensitive(false);
482 set_marked_for_display (false);
485 hide_button.set_sensitive(true);
489 AutomationTimeAxisView::build_display_menu ()
491 using namespace Menu_Helpers;
495 TimeAxisView::build_display_menu ();
497 /* now fill it with our stuff */
499 MenuList& items = display_menu->items();
501 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
502 items.push_back (SeparatorElem());
503 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
504 items.push_back (SeparatorElem());
508 Menu* auto_state_menu = manage (new Menu);
509 auto_state_menu->set_name ("ArdourContextMenu");
510 MenuList& as_items = auto_state_menu->items();
512 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
513 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
515 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
517 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
518 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
520 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
522 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
523 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
524 (AutoState) Write)));
525 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
527 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
528 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
529 (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"), sigc::bind (
545 sigc::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 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
551 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
552 AutomationList::Linear)));
553 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
555 // Set default interpolation type to linear if this isn't a (usually) discrete controller
556 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
557 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
560 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
563 /* make sure the automation menu state is correct */
565 automation_state_changed ();
566 interpolation_changed ();
570 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
577 _canvas_display->w2i (x, y);
579 /* compute vertical fractional position */
581 y = 1.0 - (y / height);
585 _line->view_to_model_coord (x, y);
587 _session->begin_reversible_command (_("add automation event"));
588 XMLNode& before = _control->alist()->get_state();
590 _control->alist()->add (when, y);
592 XMLNode& after = _control->alist()->get_state();
593 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
595 _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 when = (*x)->when;
638 double val = (*x)->value;
639 line.model_to_view_coord (when, val);
649 AutomationTimeAxisView::reset_objects (PointSelection& selection)
651 reset_objects_one (*_line, selection);
655 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
657 boost::shared_ptr<AutomationList> alist(line.the_list());
659 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
661 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
663 if ((*i).track != this) {
667 alist->reset_range ((*i).start, (*i).end);
672 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
674 return cut_copy_clear_objects_one (*_line, selection, op);
678 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
680 boost::shared_ptr<Evoral::ControlList> what_we_got;
681 boost::shared_ptr<AutomationList> alist(line.the_list());
684 XMLNode &before = alist->get_state();
686 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
688 if ((*i).track != this) {
694 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
695 _editor.get_cut_buffer().add (what_we_got);
696 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
701 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
702 _editor.get_cut_buffer().add (what_we_got);
707 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
708 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
718 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
719 double when = (*x)->when;
720 double val = (*x)->value;
721 line.model_to_view_coord (when, val);
731 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
733 return paste_one (*_line, pos, times, selection, nth);
737 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
739 AutomationSelection::iterator p;
740 boost::shared_ptr<AutomationList> alist(line.the_list());
742 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
744 if (p == selection.lines.end()) {
748 /* Make a copy of the list because we have to scale the
749 values from view coordinates to model coordinates, and we're
750 not supposed to modify the points in the selection.
753 AutomationList copy (**p);
755 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
756 double when = (*x)->when;
757 double val = (*x)->value;
758 line.view_to_model_coord (when, val);
763 XMLNode &before = alist->get_state();
764 alist->paste (copy, pos, times);
765 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
771 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
773 if (_line && touched (top, bot)) {
777 /* remember: this is X Window - coordinate space starts in upper left and moves down.
778 _y_position is the "origin" or "top" of the track.
781 double mybot = _y_position + height;
783 if (_y_position >= top && mybot <= bot) {
785 /* _y_position is below top, mybot is above bot, so we're fully
794 /* top and bot are within _y_position .. mybot */
796 topfrac = 1.0 - ((top - _y_position) / height);
797 botfrac = 1.0 - ((bot - _y_position) / height);
801 _line->get_selectables (start, end, botfrac, topfrac, results);
806 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
809 _line->get_inverted_selectables (sel, result);
813 AutomationTimeAxisView::set_selected_points (PointSelection& points)
816 _line->set_selected_points (points);
821 AutomationTimeAxisView::clear_lines ()
824 automation_connection.disconnect ();
828 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
832 assert(line->the_list() == _control->list());
834 _control->alist()->automation_state_changed.connect (automation_connection, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context());
837 //_controller = AutomationController::create(_session, line->the_list(), _control);
839 line->set_height (height);
841 /* pick up the current state */
842 automation_state_changed ();
848 AutomationTimeAxisView::entered()
851 _line->track_entered();
855 AutomationTimeAxisView::exited ()
858 _line->track_exited();
862 AutomationTimeAxisView::color_handler ()
870 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
872 TimeAxisView::set_state (node, version);
874 XMLProperty const * type = node.property ("automation-id");
875 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
876 XMLProperty const * shown = node.property ("shown");
877 if (shown && shown->value () == "yes") {
878 set_marked_for_display (true);
879 _canvas_display->show (); /* FIXME: necessary? show_at? */
883 if (!_marked_for_display) {
891 AutomationTimeAxisView::get_state_node ()
893 TimeAxisView* state_parent = get_parent_with_state ();
896 return state_parent->get_automation_child_xml_node (_control->parameter());
903 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
905 XMLNode* xml_node = get_state_node();
907 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
912 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
914 update_extra_xml_shown (true);
916 return TimeAxisView::show_at (y, nth, parent);
920 AutomationTimeAxisView::hide ()
922 update_extra_xml_shown (false);
924 TimeAxisView::hide ();
928 AutomationTimeAxisView::set_visibility (bool yn)
930 bool changed = TimeAxisView::set_visibility (yn);
933 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));