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 const changed = (height != (uint32_t) h) || first_call_to_set_height;
385 uint32_t const normal = preset_height (HeightNormal);
386 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
388 TimeAxisView* state_parent = get_parent_with_state ();
389 assert(state_parent);
390 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
392 TimeAxisView::set_height (h);
393 _base_rect->property_y2() = h;
396 _line->set_height(h);
399 _view->set_height(h);
400 _view->update_contents_height();
404 snprintf (buf, sizeof (buf), "%u", height);
406 xml_node->add_property ("height", buf);
409 if (changed_between_small_and_normal || first_call_to_set_height) {
411 first_call_to_set_height = false;
413 if (h >= preset_height (HeightNormal)) {
414 controls_table.remove (name_hbox);
417 if (plugname_packed) {
418 controls_table.remove (*plugname);
419 plugname_packed = false;
421 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
422 plugname_packed = true;
423 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
425 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
429 name_hbox.show_all ();
432 hide_button.show_all();
434 } else if (h >= preset_height (HeightSmall)) {
435 controls_table.remove (name_hbox);
437 if (plugname_packed) {
438 controls_table.remove (*plugname);
439 plugname_packed = false;
442 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
443 controls_table.hide_all ();
446 name_hbox.show_all ();
451 } else if (h >= preset_height (HeightNormal)) {
452 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
456 if (canvas_item_visible (_canvas_display)) {
457 /* only emit the signal if the height really changed and we were visible */
458 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
464 AutomationTimeAxisView::set_samples_per_unit (double spu)
466 TimeAxisView::set_samples_per_unit (spu);
472 _view->set_samples_per_unit (spu);
476 AutomationTimeAxisView::hide_clicked ()
478 // LAME fix for refreshing the hide button
479 hide_button.set_sensitive(false);
481 set_marked_for_display (false);
484 hide_button.set_sensitive(true);
488 AutomationTimeAxisView::build_display_menu ()
490 using namespace Menu_Helpers;
494 TimeAxisView::build_display_menu ();
496 /* now fill it with our stuff */
498 MenuList& items = display_menu->items();
500 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
501 items.push_back (SeparatorElem());
502 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
503 items.push_back (SeparatorElem());
507 Menu* auto_state_menu = manage (new Menu);
508 auto_state_menu->set_name ("ArdourContextMenu");
509 MenuList& as_items = auto_state_menu->items();
511 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
512 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
514 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
516 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
517 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
519 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
521 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
522 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
523 (AutoState) Write)));
524 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
526 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
527 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
528 (AutoState) Touch)));
529 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
531 items.push_back (MenuElem (_("State"), *auto_state_menu));
535 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
537 Menu* auto_mode_menu = manage (new Menu);
538 auto_mode_menu->set_name ("ArdourContextMenu");
539 MenuList& am_items = auto_mode_menu->items();
541 RadioMenuItem::Group group;
543 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
544 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
545 AutomationList::Discrete)));
546 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
547 mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete);
549 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
550 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
551 AutomationList::Linear)));
552 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
554 // Set default interpolation type to linear if this isn't a (usually) discrete controller
555 if (EventTypeMap::instance().interpolation_of(_control->parameter()) == Evoral::ControlList::Linear) {
556 mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear);
559 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
562 /* make sure the automation menu state is correct */
564 automation_state_changed ();
565 interpolation_changed ();
569 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
576 _canvas_display->w2i (x, y);
578 /* compute vertical fractional position */
580 y = 1.0 - (y / height);
584 _line->view_to_model_coord (x, y);
586 _session->begin_reversible_command (_("add automation event"));
587 XMLNode& before = _control->alist()->get_state();
589 _control->alist()->add (when, y);
591 XMLNode& after = _control->alist()->get_state();
592 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
594 _session->set_dirty ();
598 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
600 return (_line ? cut_copy_clear_one (*_line, selection, op) : false);
604 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
606 boost::shared_ptr<Evoral::ControlList> what_we_got;
607 boost::shared_ptr<AutomationList> alist (line.the_list());
610 XMLNode &before = alist->get_state();
614 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
615 _editor.get_cut_buffer().add (what_we_got);
616 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
621 if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) {
622 _editor.get_cut_buffer().add (what_we_got);
627 if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) {
628 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
635 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
636 double when = (*x)->when;
637 double val = (*x)->value;
638 line.model_to_view_coord (when, val);
648 AutomationTimeAxisView::reset_objects (PointSelection& selection)
650 reset_objects_one (*_line, selection);
654 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
656 boost::shared_ptr<AutomationList> alist(line.the_list());
658 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
660 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
662 if ((*i).track != this) {
666 alist->reset_range ((*i).start, (*i).end);
671 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
673 return cut_copy_clear_objects_one (*_line, selection, op);
677 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
679 boost::shared_ptr<Evoral::ControlList> what_we_got;
680 boost::shared_ptr<AutomationList> alist(line.the_list());
683 XMLNode &before = alist->get_state();
685 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
687 if ((*i).track != this) {
693 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
694 _editor.get_cut_buffer().add (what_we_got);
695 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
700 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
701 _editor.get_cut_buffer().add (what_we_got);
706 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
707 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
717 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
718 double when = (*x)->when;
719 double val = (*x)->value;
720 line.model_to_view_coord (when, val);
730 AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
732 return paste_one (*_line, pos, times, selection, nth);
736 AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth)
738 AutomationSelection::iterator p;
739 boost::shared_ptr<AutomationList> alist(line.the_list());
741 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
743 if (p == selection.lines.end()) {
747 /* Make a copy of the list because we have to scale the
748 values from view coordinates to model coordinates, and we're
749 not supposed to modify the points in the selection.
752 AutomationList copy (**p);
754 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
755 double when = (*x)->when;
756 double val = (*x)->value;
757 line.view_to_model_coord (when, val);
762 XMLNode &before = alist->get_state();
763 alist->paste (copy, pos, times);
764 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
770 AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
772 if (_line && touched (top, bot)) {
776 /* remember: this is X Window - coordinate space starts in upper left and moves down.
777 _y_position is the "origin" or "top" of the track.
780 double mybot = _y_position + height;
782 if (_y_position >= top && mybot <= bot) {
784 /* _y_position is below top, mybot is above bot, so we're fully
793 /* top and bot are within _y_position .. mybot */
795 topfrac = 1.0 - ((top - _y_position) / height);
796 botfrac = 1.0 - ((bot - _y_position) / height);
800 _line->get_selectables (start, end, botfrac, topfrac, results);
805 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
808 _line->get_inverted_selectables (sel, result);
812 AutomationTimeAxisView::set_selected_points (PointSelection& points)
815 _line->set_selected_points (points);
820 AutomationTimeAxisView::clear_lines ()
823 automation_connection.disconnect ();
827 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
831 assert(line->the_list() == _control->list());
833 _control->alist()->automation_state_changed.connect (automation_connection, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context());
836 //_controller = AutomationController::create(_session, line->the_list(), _control);
838 line->set_height (height);
840 /* pick up the current state */
841 automation_state_changed ();
847 AutomationTimeAxisView::entered()
850 _line->track_entered();
854 AutomationTimeAxisView::exited ()
857 _line->track_exited();
861 AutomationTimeAxisView::color_handler ()
869 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
871 TimeAxisView::set_state (node, version);
873 XMLProperty const * type = node.property ("automation-id");
874 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
875 XMLProperty const * shown = node.property ("shown");
876 if (shown && shown->value () == "yes") {
877 set_marked_for_display (true);
878 _canvas_display->show (); /* FIXME: necessary? show_at? */
882 if (!_marked_for_display) {
890 AutomationTimeAxisView::get_state_node ()
892 TimeAxisView* state_parent = get_parent_with_state ();
895 return state_parent->get_automation_child_xml_node (_control->parameter());
902 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
904 XMLNode* xml_node = get_state_node();
906 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
911 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
913 update_extra_xml_shown (true);
915 return TimeAxisView::show_at (y, nth, parent);
919 AutomationTimeAxisView::hide ()
921 update_extra_xml_shown (false);
923 TimeAxisView::hide ();
927 AutomationTimeAxisView::set_visibility (bool yn)
929 bool changed = TimeAxisView::set_visibility (yn);
932 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));