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 AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
53 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
54 PublicEditor& e, TimeAxisView& parent, bool show_regions,
55 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
58 TimeAxisView (s, e, &parent, canvas),
62 _controller(AutomationController::create(a, c->list(), c)),
64 _view (show_regions ? new AutomationStreamView(*this) : NULL),
66 height_button (_("h")),
67 clear_button (_("clear")),
68 auto_button (X_("")) /* force addition of a label */
70 if (!have_name_font) {
71 name_font = get_font_for_style (X_("AutomationTrackName"));
72 have_name_font = true;
80 mode_discrete_item = 0;
83 ignore_state_request = false;
84 first_call_to_set_height = true;
86 _base_rect = new SimpleRect(*canvas_display);
87 _base_rect->property_x1() = 0.0;
88 _base_rect->property_y1() = 0.0;
89 _base_rect->property_x2() = editor.frame_to_pixel (max_frames);
90 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
92 /* outline ends and bottom */
93 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
94 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
96 _base_rect->set_data ("trackview", this);
98 _base_rect->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_automation_track_event),
101 _base_rect->lower_to_bottom();
103 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
105 height_button.set_name ("TrackSizeButton");
106 auto_button.set_name ("TrackVisualButton");
107 clear_button.set_name ("TrackVisualButton");
108 hide_button.set_name ("TrackRemoveButton");
110 controls_table.set_no_show_all();
112 ARDOUR_UI::instance()->tooltips().set_tip(height_button, _("track height"));
113 ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state"));
114 ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track"));
115 ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("hide track"));
117 /* rearrange the name display */
119 /* we never show these for automation tracks, so make
120 life easier and remove them.
125 /* move the name label over a bit */
127 string shortpname = _name;
128 bool shortened = false;
131 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
133 if (shortpname != _name ){
137 name_label.set_text (shortpname);
138 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
140 if (nomparent.length()) {
142 /* limit the plug name string */
144 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
145 if (pname != nomparent) {
149 plugname = new Label (pname);
150 plugname->set_name (X_("TrackPlugName"));
152 name_label.set_name (X_("TrackParameterName"));
153 controls_table.remove (name_hbox);
154 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
155 plugname_packed = true;
156 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
159 plugname_packed = false;
163 string tipname = nomparent;
164 if (!tipname.empty()) {
168 ARDOUR_UI::instance()->tooltips().set_tip(controls_ebox, tipname);
171 /* add the buttons */
172 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
173 controls_table.attach (height_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
175 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
176 controls_table.attach (clear_button, 5, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
178 /* add bar controller */
179 controls_table.attach (*_controller.get(), 0, 8, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
181 controls_table.show_all ();
183 height_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::height_clicked));
184 clear_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::clear_clicked));
185 hide_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
186 auto_button.signal_clicked().connect (mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
188 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
189 controls_base_unselected_name = X_("AutomationTrackControlsBase");
190 controls_ebox.set_name (controls_base_unselected_name);
192 controls_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
194 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
195 _control->parameter());
198 set_state (*xml_node);
201 /* ask for notifications of any new RegionViews */
207 /* no regions, just a single line for the entire track (e.g. bus gain) */
210 boost::shared_ptr<AutomationLine> line(new AutomationLine (
211 _control->parameter().to_string(),
216 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
217 line->queue_reset ();
221 /* make sure labels etc. are correct */
223 automation_state_changed ();
224 ColorsChanged.connect (mem_fun (*this, &AutomationTimeAxisView::color_handler));
227 AutomationTimeAxisView::~AutomationTimeAxisView ()
232 AutomationTimeAxisView::auto_clicked ()
234 using namespace Menu_Helpers;
236 if (automation_menu == 0) {
237 automation_menu = manage (new Menu);
238 automation_menu->set_name ("ArdourContextMenu");
239 MenuList& items (automation_menu->items());
241 items.push_back (MenuElem (_("Manual"),
242 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
243 items.push_back (MenuElem (_("Play"),
244 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
245 items.push_back (MenuElem (_("Write"),
246 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
247 items.push_back (MenuElem (_("Touch"),
248 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
251 automation_menu->popup (1, gtk_get_current_event_time());
255 AutomationTimeAxisView::set_automation_state (AutoState state)
257 if (!ignore_state_request) {
258 if (_route == _automatable) { // FIXME: ew
259 _route->set_parameter_automation_state (
260 _control->parameter(),
264 _control->list()->set_automation_state(state);
270 AutomationTimeAxisView::automation_state_changed ()
274 /* update button label */
279 state = _control->list()->automation_state ();
282 switch (state & (Off|Play|Touch|Write)) {
284 auto_button.set_label (_("Manual"));
286 ignore_state_request = true;
287 auto_off_item->set_active (true);
288 auto_play_item->set_active (false);
289 auto_touch_item->set_active (false);
290 auto_write_item->set_active (false);
291 ignore_state_request = false;
295 auto_button.set_label (_("Play"));
296 if (auto_play_item) {
297 ignore_state_request = true;
298 auto_play_item->set_active (true);
299 auto_off_item->set_active (false);
300 auto_touch_item->set_active (false);
301 auto_write_item->set_active (false);
302 ignore_state_request = false;
306 auto_button.set_label (_("Write"));
307 if (auto_write_item) {
308 ignore_state_request = true;
309 auto_write_item->set_active (true);
310 auto_off_item->set_active (false);
311 auto_play_item->set_active (false);
312 auto_touch_item->set_active (false);
313 ignore_state_request = false;
317 auto_button.set_label (_("Touch"));
318 if (auto_touch_item) {
319 ignore_state_request = true;
320 auto_touch_item->set_active (true);
321 auto_off_item->set_active (false);
322 auto_play_item->set_active (false);
323 auto_write_item->set_active (false);
324 ignore_state_request = false;
328 auto_button.set_label (_("???"));
334 AutomationTimeAxisView::interpolation_changed ()
336 AutomationList::InterpolationStyle style = _control->list()->interpolation();
338 if (mode_line_item && mode_discrete_item) {
339 if (style == AutomationList::Discrete) {
340 mode_discrete_item->set_active(true);
341 mode_line_item->set_active(false);
343 mode_line_item->set_active(true);
344 mode_discrete_item->set_active(false);
349 _line->set_interpolation(style);
353 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
355 _control->list()->set_interpolation(style);
357 _line->set_interpolation(style);
361 AutomationTimeAxisView::height_clicked ()
367 AutomationTimeAxisView::clear_clicked ()
369 _session.begin_reversible_command (_("clear automation"));
372 _session.commit_reversible_command ();
376 AutomationTimeAxisView::set_height (uint32_t h)
378 bool changed = (height != (uint32_t) h) || first_call_to_set_height;
379 bool changed_between_small_and_normal = ( (h == hSmall || h == hSmaller) ^ (height == hSmall || height == hSmaller) );
381 TimeAxisView* state_parent = get_parent_with_state ();
383 assert(state_parent);
384 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
386 TimeAxisView::set_height (h);
387 _base_rect->property_y2() = h;
390 _line->set_y_position_and_height (0, h);
393 _view->set_height(h);
394 _view->update_contents_y_position_and_height();
398 snprintf (buf, sizeof (buf), "%u", height);
399 xml_node->add_property ("height", buf);
401 if (changed_between_small_and_normal || first_call_to_set_height) {
403 first_call_to_set_height = false;
406 controls_table.remove (name_hbox);
409 if (plugname_packed) {
410 controls_table.remove (*plugname);
411 plugname_packed = false;
413 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
414 plugname_packed = true;
415 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
417 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
421 name_hbox.show_all ();
424 height_button.show();
426 hide_button.show_all();
428 } else if (h >= hSmall) {
429 controls_table.remove (name_hbox);
431 if (plugname_packed) {
432 controls_table.remove (*plugname);
433 plugname_packed = false;
436 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
437 controls_table.hide_all ();
440 name_hbox.show_all ();
443 height_button.hide();
447 } else if (h >= hNormal){
449 height_button.show();
451 hide_button.show_all();
455 /* only emit the signal if the height really changed */
456 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
461 AutomationTimeAxisView::set_samples_per_unit (double spu)
463 TimeAxisView::set_samples_per_unit (spu);
469 _view->set_samples_per_unit (spu);
473 AutomationTimeAxisView::hide_clicked ()
475 // LAME fix for refreshing the hide button
476 hide_button.set_sensitive(false);
478 set_marked_for_display (false);
481 hide_button.set_sensitive(true);
485 AutomationTimeAxisView::build_display_menu ()
487 using namespace Menu_Helpers;
489 /* get the size menu ready */
495 TimeAxisView::build_display_menu ();
497 /* now fill it with our stuff */
499 MenuList& items = display_menu->items();
501 items.push_back (MenuElem (_("Height"), *size_menu));
502 items.push_back (SeparatorElem());
503 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
504 items.push_back (SeparatorElem());
505 items.push_back (MenuElem (_("Clear"), mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
506 items.push_back (SeparatorElem());
510 Menu* auto_state_menu = manage (new Menu);
511 auto_state_menu->set_name ("ArdourContextMenu");
512 MenuList& as_items = auto_state_menu->items();
514 as_items.push_back (CheckMenuElem (_("Manual"),
515 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
516 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
518 as_items.push_back (CheckMenuElem (_("Play"),
519 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
520 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
522 as_items.push_back (CheckMenuElem (_("Write"),
523 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
524 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
526 as_items.push_back (CheckMenuElem (_("Touch"),
527 bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
528 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
530 items.push_back (MenuElem (_("State"), *auto_state_menu));
534 if (_control->parameter().type() == MidiCCAutomation) {
535 Menu* auto_mode_menu = manage (new Menu);
536 auto_mode_menu->set_name ("ArdourContextMenu");
537 MenuList& am_items = auto_mode_menu->items();
539 RadioMenuItem::Group group;
541 am_items.push_back (RadioMenuElem (group, _("Discrete"), bind (
542 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
543 AutomationList::Discrete)));
544 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
545 //mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
547 am_items.push_back (RadioMenuElem (group, _("Line"), bind (
548 mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
549 AutomationList::Linear)));
550 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
551 //mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
553 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
556 /* make sure the automation menu state is correct */
558 automation_state_changed ();
559 interpolation_changed ();
563 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
570 canvas_display->w2i (x, y);
572 /* compute vertical fractional position */
574 y = 1.0 - (y / height);
578 _line->view_to_model_y (y);
580 _session.begin_reversible_command (_("add automation event"));
581 XMLNode& before = _control->list()->get_state();
583 _control->list()->add (when, y);
585 XMLNode& after = _control->list()->get_state();
586 _session.commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->list().get(), &before, &after));
588 _session.set_dirty ();
593 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
595 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
599 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
601 AutomationList* what_we_got = 0;
602 boost::shared_ptr<AutomationList> alist (line.the_list());
605 XMLNode &before = alist->get_state();
609 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
610 editor.get_cut_buffer().add (what_we_got);
611 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
616 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
617 editor.get_cut_buffer().add (what_we_got);
622 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
623 _session.add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
632 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
633 double foo = (*x)->value;
634 line.model_to_view_y (foo);
643 AutomationTimeAxisView::reset_objects (PointSelection& selection)
645 reset_objects_one (*_line, selection);
649 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
651 boost::shared_ptr<AutomationList> alist(line.the_list());
653 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
655 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
657 if (&(*i).track != this) {
661 alist->reset_range ((*i).start, (*i).end);
666 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
668 return cut_copy_clear_objects_one (*_line, selection, op);
672 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
674 AutomationList* what_we_got = 0;
675 boost::shared_ptr<AutomationList> alist(line.the_list());
678 XMLNode &before = alist->get_state();
680 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
682 if (&(*i).track != this) {
688 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
689 editor.get_cut_buffer().add (what_we_got);
690 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
695 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
696 editor.get_cut_buffer().add (what_we_got);
701 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
702 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
714 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
715 double foo = (*x)->value;
716 line.model_to_view_y (foo);
725 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
727 return paste_one (*_line, pos, times, selection, nth);
731 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
733 AutomationSelection::iterator p;
734 boost::shared_ptr<AutomationList> alist(line.the_list());
736 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
738 if (p == selection.lines.end()) {
742 /* Make a copy of the list because we have to scale the
743 values from view coordinates to model coordinates, and we're
744 not supposed to modify the points in the selection.
747 AutomationList copy (**p);
749 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
750 double foo = (*x)->value;
751 line.view_to_model_y (foo);
755 XMLNode &before = alist->get_state();
756 alist->paste (copy, pos, times);
757 _session.add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
763 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
765 if (_line && touched (top, bot)) {
769 /* remember: this is X Window - coordinate space starts in upper left and moves down.
770 y_position is the "origin" or "top" of the track.
773 double mybot = y_position + height;
775 if (y_position >= top && mybot <= bot) {
777 /* y_position is below top, mybot is above bot, so we're fully
786 /* top and bot are within y_position .. mybot */
788 topfrac = 1.0 - ((top - y_position) / height);
789 botfrac = 1.0 - ((bot - y_position) / height);
793 _line->get_selectables (start, end, botfrac, topfrac, results);
798 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
801 _line->get_inverted_selectables (sel, result);
805 AutomationTimeAxisView::set_selected_points (PointSelection& points)
808 _line->set_selected_points (points);
812 AutomationTimeAxisView::clear_lines ()
815 automation_connection.disconnect ();
819 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
823 assert(line->the_list() == _control->list());
825 automation_connection = _control->list()->automation_state_changed.connect
826 (mem_fun(*this, &AutomationTimeAxisView::automation_state_changed));
829 //_controller = AutomationController::create(_session, line->the_list(), _control);
831 line->set_y_position_and_height (0, height);
833 /* pick up the current state */
834 automation_state_changed ();
840 AutomationTimeAxisView::entered()
843 _line->track_entered();
847 AutomationTimeAxisView::exited ()
850 _line->track_exited();
854 AutomationTimeAxisView::set_colors ()
856 for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
865 AutomationTimeAxisView::color_handler ()
873 AutomationTimeAxisView::set_state (const XMLNode& node)
875 return TimeAxisView::set_state (node);
878 XMLNodeConstIterator iter;
880 kids = node.children ();
882 for (iter = kids.begin(); iter != kids.end(); ++iter) {
884 if ((*iter)->name() == state_node_name) {
885 XMLProperty* type = (*iter)->property("automation-id");
887 if (type && type->value() == _control->parameter().to_string()) {
888 XMLProperty *shown = (*iter)->property("shown_editor");
890 if (shown && shown->value() == "yes") {
891 set_marked_for_display(true);
892 canvas_display->show(); /* FIXME: necessary? show_at? */
899 if (!_marked_for_display)
904 AutomationTimeAxisView::get_state_node ()
906 TimeAxisView* state_parent = get_parent_with_state ();
909 return state_parent->get_automation_child_xml_node (_control->parameter());
916 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
918 XMLNode* xml_node = get_state_node();
920 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
925 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
927 update_extra_xml_shown (true);
929 return TimeAxisView::show_at (y, nth, parent);
933 AutomationTimeAxisView::hide ()
935 update_extra_xml_shown (false);
937 TimeAxisView::hide ();