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 "point_selection.h"
39 #include "canvas_impl.h"
45 using namespace ARDOUR;
48 using namespace Gtkmm2ext;
49 using namespace Editing;
51 Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
52 bool AutomationTimeAxisView::have_name_font = false;
53 const string AutomationTimeAxisView::state_node_name = "AutomationChild";
56 /** \a a the automatable object this time axis is to display data for.
57 * For route/track automation (e.g. gain) pass the route for both \r and \a.
58 * For route child (e.g. plugin) automation, pass the child for \a.
59 * For region automation (e.g. MIDI CC), pass null for \a.
61 AutomationTimeAxisView::AutomationTimeAxisView (Session* s, boost::shared_ptr<Route> r,
62 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
63 PublicEditor& e, TimeAxisView& parent, bool show_regions,
64 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
66 TimeAxisView (s, e, &parent, canvas),
70 _controller(AutomationController::create(a, c->parameter(), c)),
72 _view (show_regions ? new AutomationStreamView(*this) : NULL),
74 auto_button (X_("")) /* force addition of a label */
76 if (!have_name_font) {
77 name_font = get_font_for_style (X_("AutomationTrackName"));
78 have_name_font = true;
86 mode_discrete_item = 0;
89 ignore_state_request = false;
90 first_call_to_set_height = true;
92 _base_rect = new SimpleRect(*_canvas_display);
93 _base_rect->property_x1() = 0.0;
94 _base_rect->property_y1() = 0.0;
95 _base_rect->property_x2() = LONG_MAX - 2;
96 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
98 /* outline ends and bottom */
99 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
100 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
102 _base_rect->set_data ("trackview", this);
104 _base_rect->signal_event().connect (sigc::bind (
105 sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
109 _base_rect->lower_to_bottom();
112 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
114 auto_button.set_name ("TrackVisualButton");
115 hide_button.set_name ("TrackRemoveButton");
117 auto_button.unset_flags (Gtk::CAN_FOCUS);
118 hide_button.unset_flags (Gtk::CAN_FOCUS);
120 controls_table.set_no_show_all();
122 ARDOUR_UI::instance()->set_tip(auto_button, _("automation state"));
123 ARDOUR_UI::instance()->set_tip(hide_button, _("hide track"));
125 /* rearrange the name display */
127 /* we never show these for automation tracks, so make
128 life easier and remove them.
133 /* move the name label over a bit */
135 string shortpname = _name;
136 bool shortened = false;
139 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
141 if (shortpname != _name ){
145 name_label.set_text (shortpname);
146 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
148 if (nomparent.length()) {
150 /* limit the plug name string */
152 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
153 if (pname != nomparent) {
157 plugname = new Label (pname);
158 plugname->set_name (X_("TrackPlugName"));
160 name_label.set_name (X_("TrackParameterName"));
161 controls_table.remove (name_hbox);
162 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
163 plugname_packed = true;
164 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
167 plugname_packed = false;
171 string tipname = nomparent;
172 if (!tipname.empty()) {
176 ARDOUR_UI::instance()->set_tip(controls_ebox, tipname);
179 /* add the buttons */
180 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
182 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
184 /* add bar controller */
185 controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
187 controls_table.show_all ();
189 hide_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
190 auto_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
192 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
193 controls_base_unselected_name = X_("AutomationTrackControlsBase");
194 controls_ebox.set_name (controls_base_unselected_name);
196 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (
197 _control->parameter(), Stateful::loading_state_version
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) {
264 _automatable->set_parameter_automation_state (_control->parameter(), state);
267 if (_route == _automatable) { // This is a time axis for route (not region) automation
268 _route->set_parameter_automation_state (_control->parameter(), state);
271 if (_control->list()) {
272 _control->alist()->set_automation_state(state);
276 _view->set_automation_state (state);
278 /* AutomationStreamViews don't signal when their automation state changes, so handle
279 our updates `manually'.
281 automation_state_changed ();
286 AutomationTimeAxisView::automation_state_changed ()
290 /* update button label */
293 state = _control->alist()->automation_state ();
295 state = _view->automation_state ();
300 switch (state & (Off|Play|Touch|Write)) {
302 auto_button.set_label (_("Manual"));
304 ignore_state_request = true;
305 auto_off_item->set_active (true);
306 auto_play_item->set_active (false);
307 auto_touch_item->set_active (false);
308 auto_write_item->set_active (false);
309 ignore_state_request = false;
313 auto_button.set_label (_("Play"));
314 if (auto_play_item) {
315 ignore_state_request = true;
316 auto_play_item->set_active (true);
317 auto_off_item->set_active (false);
318 auto_touch_item->set_active (false);
319 auto_write_item->set_active (false);
320 ignore_state_request = false;
324 auto_button.set_label (_("Write"));
325 if (auto_write_item) {
326 ignore_state_request = true;
327 auto_write_item->set_active (true);
328 auto_off_item->set_active (false);
329 auto_play_item->set_active (false);
330 auto_touch_item->set_active (false);
331 ignore_state_request = false;
335 auto_button.set_label (_("Touch"));
336 if (auto_touch_item) {
337 ignore_state_request = true;
338 auto_touch_item->set_active (true);
339 auto_off_item->set_active (false);
340 auto_play_item->set_active (false);
341 auto_write_item->set_active (false);
342 ignore_state_request = false;
346 auto_button.set_label (_("???"));
351 /** The interpolation style of our AutomationList has changed, so update */
353 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
355 if (mode_line_item && mode_discrete_item) {
356 if (s == AutomationList::Discrete) {
357 mode_discrete_item->set_active(true);
358 mode_line_item->set_active(false);
360 mode_line_item->set_active(true);
361 mode_discrete_item->set_active(false);
366 /** A menu item has been selected to change our interpolation mode */
368 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
370 /* Tell our view's list, if we have one, otherwise tell our own.
371 * Everything else will be signalled back from that.
375 _view->set_interpolation (style);
377 _control->list()->set_interpolation (style);
382 AutomationTimeAxisView::clear_clicked ()
384 assert (_line || _view);
386 _session->begin_reversible_command (_("clear automation"));
394 _session->commit_reversible_command ();
395 _session->set_dirty ();
399 AutomationTimeAxisView::set_height (uint32_t h)
401 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
402 uint32_t const normal = preset_height (HeightNormal);
403 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
405 TimeAxisView* state_parent = get_parent_with_state ();
406 assert(state_parent);
407 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter(), Stateful::loading_state_version);
409 TimeAxisView::set_height (h);
410 _base_rect->property_y2() = h;
413 _line->set_height(h);
417 _view->set_height(h);
418 _view->update_contents_height();
422 snprintf (buf, sizeof (buf), "%u", height);
424 xml_node->add_property ("height", buf);
427 if (changed_between_small_and_normal || first_call_to_set_height) {
429 first_call_to_set_height = false;
431 if (h >= preset_height (HeightNormal)) {
432 controls_table.remove (name_hbox);
435 if (plugname_packed) {
436 controls_table.remove (*plugname);
437 plugname_packed = false;
439 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
440 plugname_packed = true;
441 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
443 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
447 name_hbox.show_all ();
450 hide_button.show_all();
452 } else if (h >= preset_height (HeightSmall)) {
453 controls_table.remove (name_hbox);
455 if (plugname_packed) {
456 controls_table.remove (*plugname);
457 plugname_packed = false;
460 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
461 controls_table.hide_all ();
464 name_hbox.show_all ();
469 } else if (h >= preset_height (HeightNormal)) {
470 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
474 if (canvas_item_visible (_canvas_display)) {
475 /* only emit the signal if the height really changed and we were visible */
476 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
482 AutomationTimeAxisView::set_samples_per_unit (double spu)
484 TimeAxisView::set_samples_per_unit (spu);
491 _view->set_samples_per_unit (spu);
496 AutomationTimeAxisView::hide_clicked ()
498 // LAME fix for refreshing the hide button
499 hide_button.set_sensitive(false);
501 set_marked_for_display (false);
504 hide_button.set_sensitive(true);
508 AutomationTimeAxisView::build_display_menu ()
510 using namespace Menu_Helpers;
514 TimeAxisView::build_display_menu ();
516 /* now fill it with our stuff */
518 MenuList& items = display_menu->items();
520 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
521 items.push_back (SeparatorElem());
522 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
523 items.push_back (SeparatorElem());
527 Menu* auto_state_menu = manage (new Menu);
528 auto_state_menu->set_name ("ArdourContextMenu");
529 MenuList& as_items = auto_state_menu->items();
531 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
532 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
534 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
536 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
537 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
539 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
541 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
542 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
543 (AutoState) Write)));
544 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
546 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
547 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
548 (AutoState) Touch)));
549 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
551 items.push_back (MenuElem (_("State"), *auto_state_menu));
555 /* current interpolation state */
556 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
558 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
560 Menu* auto_mode_menu = manage (new Menu);
561 auto_mode_menu->set_name ("ArdourContextMenu");
562 MenuList& am_items = auto_mode_menu->items();
564 RadioMenuItem::Group group;
566 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
567 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
568 AutomationList::Discrete)));
569 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
570 mode_discrete_item->set_active (s == AutomationList::Discrete);
572 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
573 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
574 AutomationList::Linear)));
575 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
576 mode_line_item->set_active (s == AutomationList::Linear);
578 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
581 /* make sure the automation menu state is correct */
583 automation_state_changed ();
584 interpolation_changed (s);
588 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
595 _canvas_display->w2i (x, y);
597 /* compute vertical fractional position */
599 y = 1.0 - (y / height);
603 _line->view_to_model_coord (x, y);
605 _session->begin_reversible_command (_("add automation event"));
606 XMLNode& before = _control->alist()->get_state();
608 _control->alist()->add (when, y);
610 XMLNode& after = _control->alist()->get_state();
611 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
613 _session->set_dirty ();
617 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
619 list<boost::shared_ptr<AutomationLine> > lines;
621 lines.push_back (_line);
623 lines = _view->get_lines ();
626 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
627 cut_copy_clear_one (**i, selection, op);
632 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
634 boost::shared_ptr<Evoral::ControlList> what_we_got;
635 boost::shared_ptr<AutomationList> alist (line.the_list());
637 XMLNode &before = alist->get_state();
639 /* convert time selection to automation list model coordinates */
640 const Evoral::TimeConverter<double, ARDOUR::sframes_t>& tc = line.time_converter ();
641 double const start = tc.from (selection.time.front().start - tc.origin_b ());
642 double const end = tc.from (selection.time.front().end - tc.origin_b ());
647 if ((what_we_got = alist->cut (start, end)) != 0) {
648 _editor.get_cut_buffer().add (what_we_got);
649 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
653 if ((what_we_got = alist->copy (start, end)) != 0) {
654 _editor.get_cut_buffer().add (what_we_got);
659 if ((what_we_got = alist->cut (start, end)) != 0) {
660 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
666 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
667 double when = (*x)->when;
668 double val = (*x)->value;
669 line.model_to_view_coord (when, val);
677 AutomationTimeAxisView::reset_objects (PointSelection& selection)
679 list<boost::shared_ptr<AutomationLine> > lines;
681 lines.push_back (_line);
683 lines = _view->get_lines ();
686 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
687 reset_objects_one (**i, selection);
692 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
694 boost::shared_ptr<AutomationList> alist(line.the_list());
696 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
698 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
700 if ((*i).track != this) {
704 alist->reset_range ((*i).start, (*i).end);
709 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
711 list<boost::shared_ptr<AutomationLine> > lines;
713 lines.push_back (_line);
715 lines = _view->get_lines ();
718 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
719 cut_copy_clear_objects_one (**i, selection, op);
724 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
726 boost::shared_ptr<Evoral::ControlList> what_we_got;
727 boost::shared_ptr<AutomationList> alist(line.the_list());
729 XMLNode &before = alist->get_state();
731 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
733 if ((*i).track != this) {
739 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
740 _editor.get_cut_buffer().add (what_we_got);
741 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
745 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
746 _editor.get_cut_buffer().add (what_we_got);
751 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
752 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
761 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
762 double when = (*x)->when;
763 double val = (*x)->value;
764 line.model_to_view_coord (when, val);
771 /** Paste a selection.
772 * @param pos Position to paste to (session frames).
773 * @param times Number of times to paste.
774 * @param selection Selection to paste.
775 * @param nth Index of the AutomationList within the selection to paste from.
778 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
780 boost::shared_ptr<AutomationLine> line;
785 line = _view->paste_line (pos);
792 return paste_one (*line, pos, times, selection, nth);
796 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
798 AutomationSelection::iterator p;
799 boost::shared_ptr<AutomationList> alist(line.the_list());
801 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
803 if (p == selection.lines.end()) {
807 /* Make a copy of the list because we have to scale the
808 values from view coordinates to model coordinates, and we're
809 not supposed to modify the points in the selection.
812 AutomationList copy (**p);
814 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
815 double when = (*x)->when;
816 double val = (*x)->value;
817 line.view_to_model_coord (when, val);
822 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
824 XMLNode &before = alist->get_state();
825 alist->paste (copy, model_pos, times);
826 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
832 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
834 if (!_line && !_view) {
838 if (touched (top, bot)) {
840 /* remember: this is X Window - coordinate space starts in upper left and moves down.
841 _y_position is the "origin" or "top" of the track.
844 /* bottom of our track */
845 double const mybot = _y_position + height;
850 if (_y_position >= top && mybot <= bot) {
852 /* _y_position is below top, mybot is above bot, so we're fully
861 /* top and bot are within _y_position .. mybot */
863 topfrac = 1.0 - ((top - _y_position) / height);
864 botfrac = 1.0 - ((bot - _y_position) / height);
869 _line->get_selectables (start, end, botfrac, topfrac, results);
871 _view->get_selectables (start, end, botfrac, topfrac, results);
877 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
880 _line->get_inverted_selectables (sel, result);
885 AutomationTimeAxisView::set_selected_points (PointSelection& points)
888 _line->set_selected_points (points);
890 _view->set_selected_points (points);
895 AutomationTimeAxisView::clear_lines ()
898 _list_connections.drop_connections ();
902 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
906 assert(line->the_list() == _control->list());
908 _control->alist()->automation_state_changed.connect (
909 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
912 _control->alist()->InterpolationChanged.connect (
913 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
917 //_controller = AutomationController::create(_session, line->the_list(), _control);
919 line->set_height (height);
921 /* pick up the current state */
922 automation_state_changed ();
928 AutomationTimeAxisView::entered()
931 _line->track_entered();
935 AutomationTimeAxisView::exited ()
938 _line->track_exited();
942 AutomationTimeAxisView::color_handler ()
950 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
952 TimeAxisView::set_state (node, version);
954 if (version < 3000) {
955 return set_state_2X (node, version);
958 XMLProperty const * type = node.property ("automation-id");
959 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
960 XMLProperty const * shown = node.property ("shown");
961 if (shown && shown->value () == "yes") {
962 set_marked_for_display (true);
963 _canvas_display->show (); /* FIXME: necessary? show_at? */
967 if (!_marked_for_display) {
975 AutomationTimeAxisView::set_state_2X (const XMLNode& node, int version)
977 if (node.name() == X_("gain") && _control->parameter() == Evoral::Parameter (GainAutomation)) {
978 XMLProperty const * shown = node.property (X_("shown"));
979 if (shown && string_is_affirmative (shown->value ())) {
980 set_marked_for_display (true);
981 _canvas_display->show (); /* FIXME: necessary? show_at? */
985 if (!_marked_for_display) {
993 AutomationTimeAxisView::get_state_node ()
995 TimeAxisView* state_parent = get_parent_with_state ();
998 return state_parent->get_automation_child_xml_node (_control->parameter(), Stateful::loading_state_version);
1005 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
1007 XMLNode* xml_node = get_state_node();
1009 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
1014 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
1016 update_extra_xml_shown (true);
1018 return TimeAxisView::show_at (y, nth, parent);
1022 AutomationTimeAxisView::hide ()
1024 update_extra_xml_shown (false);
1026 TimeAxisView::hide ();
1030 AutomationTimeAxisView::set_visibility (bool yn)
1032 bool changed = TimeAxisView::set_visibility (yn);
1035 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1041 /** @return true if this view has any automation data to display */
1043 AutomationTimeAxisView::has_automation () const
1045 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );