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()->tooltips().set_tip(auto_button, _("automation state"));
124 ARDOUR_UI::instance()->tooltips().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()->tooltips().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 /* only emit the signal if the height really changed */
458 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
463 AutomationTimeAxisView::set_samples_per_unit (double spu)
465 TimeAxisView::set_samples_per_unit (spu);
471 _view->set_samples_per_unit (spu);
475 AutomationTimeAxisView::hide_clicked ()
477 // LAME fix for refreshing the hide button
478 hide_button.set_sensitive(false);
480 set_marked_for_display (false);
483 hide_button.set_sensitive(true);
487 AutomationTimeAxisView::build_display_menu ()
489 using namespace Menu_Helpers;
491 /* get the size menu ready */
497 TimeAxisView::build_display_menu ();
499 /* now fill it with our stuff */
501 MenuList& items = display_menu->items();
503 items.push_back (MenuElem (_("Height"), *size_menu));
504 items.push_back (SeparatorElem());
505 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
506 items.push_back (SeparatorElem());
507 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
508 items.push_back (SeparatorElem());
512 Menu* auto_state_menu = manage (new Menu);
513 auto_state_menu->set_name ("ArdourContextMenu");
514 MenuList& as_items = auto_state_menu->items();
516 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
517 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
519 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
521 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
522 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
524 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
526 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
527 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
528 (AutoState) Write)));
529 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
531 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
532 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
533 (AutoState) Touch)));
534 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
536 items.push_back (MenuElem (_("State"), *auto_state_menu));
540 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
542 Menu* auto_mode_menu = manage (new Menu);
543 auto_mode_menu->set_name ("ArdourContextMenu");
544 MenuList& am_items = auto_mode_menu->items();
546 RadioMenuItem::Group group;
548 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
549 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
550 AutomationList::Discrete)));
551 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
552 mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
554 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
555 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
556 AutomationList::Linear)));
557 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
559 // Set default interpolation type to linear if this isn't a (usually) discrete controller
560 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
561 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
564 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
567 /* make sure the automation menu state is correct */
569 automation_state_changed ();
570 interpolation_changed ();
574 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
581 _canvas_display->w2i (x, y);
583 /* compute vertical fractional position */
585 y = 1.0 - (y / height);
589 _line->view_to_model_coord (x, y);
591 _session->begin_reversible_command (_("add automation event"));
592 XMLNode& before = _control->alist()->get_state();
594 _control->alist()->add (when, y);
596 XMLNode& after = _control->alist()->get_state();
597 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
599 _session->set_dirty ();
603 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
605 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
609 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
611 boost::shared_ptr<Evoral::ControlList> what_we_got;
612 boost::shared_ptr<AutomationList> alist (line.the_list());
615 XMLNode &before = alist->get_state();
619 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
620 _editor.get_cut_buffer().add (what_we_got);
621 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
626 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
627 _editor.get_cut_buffer().add (what_we_got);
632 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
633 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
640 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
641 double when = (*x)->when;
642 double val = (*x)->value;
643 line.model_to_view_coord (when, val);
653 AutomationTimeAxisView::reset_objects (PointSelection& selection)
655 reset_objects_one (*_line, selection);
659 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
661 boost::shared_ptr<AutomationList> alist(line.the_list());
663 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
665 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
667 if ((*i).track != this) {
671 alist->reset_range ((*i).start, (*i).end);
676 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
678 return cut_copy_clear_objects_one (*_line, selection, op);
682 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
684 boost::shared_ptr<Evoral::ControlList> what_we_got;
685 boost::shared_ptr<AutomationList> alist(line.the_list());
688 XMLNode &before = alist->get_state();
690 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
692 if ((*i).track != this) {
698 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
699 _editor.get_cut_buffer().add (what_we_got);
700 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
705 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
706 _editor.get_cut_buffer().add (what_we_got);
711 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
712 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
722 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
723 double when = (*x)->when;
724 double val = (*x)->value;
725 line.model_to_view_coord (when, val);
735 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
737 return paste_one (*_line, pos, times, selection, nth);
741 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
743 AutomationSelection::iterator p;
744 boost::shared_ptr<AutomationList> alist(line.the_list());
746 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
748 if (p == selection.lines.end()) {
752 /* Make a copy of the list because we have to scale the
753 values from view coordinates to model coordinates, and we're
754 not supposed to modify the points in the selection.
757 AutomationList copy (**p);
759 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
760 double when = (*x)->when;
761 double val = (*x)->value;
762 line.view_to_model_coord (when, val);
767 XMLNode &before = alist->get_state();
768 alist->paste (copy, pos, times);
769 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
775 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
777 if (_line && touched (top, bot)) {
781 /* remember: this is X Window - coordinate space starts in upper left and moves down.
782 _y_position is the "origin" or "top" of the track.
785 double mybot = _y_position + height;
787 if (_y_position >= top && mybot <= bot) {
789 /* _y_position is below top, mybot is above bot, so we're fully
798 /* top and bot are within _y_position .. mybot */
800 topfrac = 1.0 - ((top - _y_position) / height);
801 botfrac = 1.0 - ((bot - _y_position) / height);
805 _line->get_selectables (start, end, botfrac, topfrac, results);
810 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
813 _line->get_inverted_selectables (sel, result);
817 AutomationTimeAxisView::set_selected_points (PointSelection& points)
820 _line->set_selected_points (points);
825 AutomationTimeAxisView::clear_lines ()
828 automation_connection.disconnect ();
832 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
836 assert(line->the_list() == _control->list());
838 _control->alist()->automation_state_changed.connect (automation_connection, boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context());
841 //_controller = AutomationController::create(_session, line->the_list(), _control);
843 line->set_height (height);
845 /* pick up the current state */
846 automation_state_changed ();
852 AutomationTimeAxisView::entered()
855 _line->track_entered();
859 AutomationTimeAxisView::exited ()
862 _line->track_exited();
866 AutomationTimeAxisView::color_handler ()
874 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
876 TimeAxisView::set_state (node, version);
878 XMLProperty const * type = node.property ("automation-id");
879 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
880 XMLProperty const * shown = node.property ("shown");
881 if (shown && shown->value () == "yes") {
882 set_marked_for_display (true);
883 _canvas_display->show (); /* FIXME: necessary? show_at? */
887 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 ();