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 (_("???"));
349 /** The interpolation style of our AutomationList has changed, so update */
351 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
353 if (mode_line_item && mode_discrete_item) {
354 if (s == AutomationList::Discrete) {
355 mode_discrete_item->set_active(true);
356 mode_line_item->set_active(false);
358 mode_line_item->set_active(true);
359 mode_discrete_item->set_active(false);
364 /** A menu item has been selected to change our interpolation mode */
366 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
368 /* Tell our view's list, if we have one, otherwise tell our own.
369 * Everything else will be signalled back from that.
373 _view->set_interpolation (style);
375 _control->list()->set_interpolation (style);
380 AutomationTimeAxisView::clear_clicked ()
383 _session->begin_reversible_command (_("clear automation"));
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 /* current interpolation state */
543 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
545 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
547 Menu* auto_mode_menu = manage (new Menu);
548 auto_mode_menu->set_name ("ArdourContextMenu");
549 MenuList& am_items = auto_mode_menu->items();
551 RadioMenuItem::Group group;
553 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
554 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
555 AutomationList::Discrete)));
556 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
557 mode_discrete_item->set_active (s == AutomationList::Discrete);
559 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
560 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
561 AutomationList::Linear)));
562 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
563 mode_line_item->set_active (s == AutomationList::Linear);
565 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
568 /* make sure the automation menu state is correct */
570 automation_state_changed ();
571 interpolation_changed (s);
575 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
582 _canvas_display->w2i (x, y);
584 /* compute vertical fractional position */
586 y = 1.0 - (y / height);
590 _line->view_to_model_coord (x, y);
592 _session->begin_reversible_command (_("add automation event"));
593 XMLNode& before = _control->alist()->get_state();
595 _control->alist()->add (when, y);
597 XMLNode& after = _control->alist()->get_state();
598 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
600 _session->set_dirty ();
604 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
606 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
610 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
612 boost::shared_ptr<Evoral::ControlList> what_we_got;
613 boost::shared_ptr<AutomationList> alist (line.the_list());
616 XMLNode &before = alist->get_state();
620 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
621 _editor.get_cut_buffer().add (what_we_got);
622 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
627 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
628 _editor.get_cut_buffer().add (what_we_got);
633 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
634 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
641 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
642 double when = (*x)->when;
643 double val = (*x)->value;
644 line.model_to_view_coord (when, val);
654 AutomationTimeAxisView::reset_objects (PointSelection& selection)
656 reset_objects_one (*_line, selection);
660 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
662 boost::shared_ptr<AutomationList> alist(line.the_list());
664 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
666 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
668 if ((*i).track != this) {
672 alist->reset_range ((*i).start, (*i).end);
677 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
679 return cut_copy_clear_objects_one (*_line, selection, op);
683 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
685 boost::shared_ptr<Evoral::ControlList> what_we_got;
686 boost::shared_ptr<AutomationList> alist(line.the_list());
689 XMLNode &before = alist->get_state();
691 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
693 if ((*i).track != this) {
699 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
700 _editor.get_cut_buffer().add (what_we_got);
701 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
706 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
707 _editor.get_cut_buffer().add (what_we_got);
712 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
713 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
723 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
724 double when = (*x)->when;
725 double val = (*x)->value;
726 line.model_to_view_coord (when, val);
736 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
738 return paste_one (*_line, pos, times, selection, nth);
742 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
744 AutomationSelection::iterator p;
745 boost::shared_ptr<AutomationList> alist(line.the_list());
747 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
749 if (p == selection.lines.end()) {
753 /* Make a copy of the list because we have to scale the
754 values from view coordinates to model coordinates, and we're
755 not supposed to modify the points in the selection.
758 AutomationList copy (**p);
760 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
761 double when = (*x)->when;
762 double val = (*x)->value;
763 line.view_to_model_coord (when, val);
768 XMLNode &before = alist->get_state();
769 alist->paste (copy, pos, times);
770 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
776 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
778 if (_line && touched (top, bot)) {
782 /* remember: this is X Window - coordinate space starts in upper left and moves down.
783 _y_position is the "origin" or "top" of the track.
786 double mybot = _y_position + height;
788 if (_y_position >= top && mybot <= bot) {
790 /* _y_position is below top, mybot is above bot, so we're fully
799 /* top and bot are within _y_position .. mybot */
801 topfrac = 1.0 - ((top - _y_position) / height);
802 botfrac = 1.0 - ((bot - _y_position) / height);
806 _line->get_selectables (start, end, botfrac, topfrac, results);
811 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
814 _line->get_inverted_selectables (sel, result);
818 AutomationTimeAxisView::set_selected_points (PointSelection& points)
821 _line->set_selected_points (points);
826 AutomationTimeAxisView::clear_lines ()
829 _list_connections.drop_connections ();
833 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
837 assert(line->the_list() == _control->list());
839 _control->alist()->automation_state_changed.connect (
840 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
843 _control->alist()->InterpolationChanged.connect (
844 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
848 //_controller = AutomationController::create(_session, line->the_list(), _control);
850 line->set_height (height);
852 /* pick up the current state */
853 automation_state_changed ();
859 AutomationTimeAxisView::entered()
862 _line->track_entered();
866 AutomationTimeAxisView::exited ()
869 _line->track_exited();
873 AutomationTimeAxisView::color_handler ()
881 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
883 TimeAxisView::set_state (node, version);
885 XMLProperty const * type = node.property ("automation-id");
886 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
887 XMLProperty const * shown = node.property ("shown");
888 if (shown && shown->value () == "yes") {
889 set_marked_for_display (true);
890 _canvas_display->show (); /* FIXME: necessary? show_at? */
894 if (!_marked_for_display) {
902 AutomationTimeAxisView::get_state_node ()
904 TimeAxisView* state_parent = get_parent_with_state ();
907 return state_parent->get_automation_child_xml_node (_control->parameter());
914 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
916 XMLNode* xml_node = get_state_node();
918 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
923 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
925 update_extra_xml_shown (true);
927 return TimeAxisView::show_at (y, nth, parent);
931 AutomationTimeAxisView::hide ()
933 update_extra_xml_shown (false);
935 TimeAxisView::hide ();
939 AutomationTimeAxisView::set_visibility (bool yn)
941 bool changed = TimeAxisView::set_visibility (yn);
944 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
950 /** @return true if this view has any automation data to display */
952 AutomationTimeAxisView::has_automation () const
954 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );