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());
200 set_state (*xml_node, Stateful::loading_state_version);
203 /* ask for notifications of any new RegionViews */
209 /* no regions, just a single line for the entire track (e.g. bus gain) */
211 boost::shared_ptr<AutomationLine> line(new AutomationLine (
212 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
217 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
218 line->queue_reset ();
222 /* make sure labels etc. are correct */
224 automation_state_changed ();
225 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
228 AutomationTimeAxisView::~AutomationTimeAxisView ()
233 AutomationTimeAxisView::auto_clicked ()
235 using namespace Menu_Helpers;
237 if (automation_menu == 0) {
238 automation_menu = manage (new Menu);
239 automation_menu->set_name ("ArdourContextMenu");
240 MenuList& items (automation_menu->items());
242 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
243 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
244 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
245 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
246 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
247 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
248 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
249 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
252 automation_menu->popup (1, gtk_get_current_event_time());
256 AutomationTimeAxisView::set_automation_state (AutoState state)
258 if (ignore_state_request) {
263 _automatable->set_parameter_automation_state (_control->parameter(), state);
266 if (_route == _automatable) { // This is a time axis for route (not region) automation
267 _route->set_parameter_automation_state (_control->parameter(), state);
270 if (_control->list()) {
271 _control->alist()->set_automation_state(state);
275 _view->set_automation_state (state);
277 /* AutomationStreamViews don't signal when their automation state changes, so handle
278 our updates `manually'.
280 automation_state_changed ();
285 AutomationTimeAxisView::automation_state_changed ()
289 /* update button label */
292 state = _control->alist()->automation_state ();
294 state = _view->automation_state ();
299 switch (state & (Off|Play|Touch|Write)) {
301 auto_button.set_label (_("Manual"));
303 ignore_state_request = true;
304 auto_off_item->set_active (true);
305 auto_play_item->set_active (false);
306 auto_touch_item->set_active (false);
307 auto_write_item->set_active (false);
308 ignore_state_request = false;
312 auto_button.set_label (_("Play"));
313 if (auto_play_item) {
314 ignore_state_request = true;
315 auto_play_item->set_active (true);
316 auto_off_item->set_active (false);
317 auto_touch_item->set_active (false);
318 auto_write_item->set_active (false);
319 ignore_state_request = false;
323 auto_button.set_label (_("Write"));
324 if (auto_write_item) {
325 ignore_state_request = true;
326 auto_write_item->set_active (true);
327 auto_off_item->set_active (false);
328 auto_play_item->set_active (false);
329 auto_touch_item->set_active (false);
330 ignore_state_request = false;
334 auto_button.set_label (_("Touch"));
335 if (auto_touch_item) {
336 ignore_state_request = true;
337 auto_touch_item->set_active (true);
338 auto_off_item->set_active (false);
339 auto_play_item->set_active (false);
340 auto_write_item->set_active (false);
341 ignore_state_request = false;
345 auto_button.set_label (_("???"));
350 /** The interpolation style of our AutomationList has changed, so update */
352 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
354 if (mode_line_item && mode_discrete_item) {
355 if (s == AutomationList::Discrete) {
356 mode_discrete_item->set_active(true);
357 mode_line_item->set_active(false);
359 mode_line_item->set_active(true);
360 mode_discrete_item->set_active(false);
365 /** A menu item has been selected to change our interpolation mode */
367 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
369 /* Tell our view's list, if we have one, otherwise tell our own.
370 * Everything else will be signalled back from that.
374 _view->set_interpolation (style);
376 _control->list()->set_interpolation (style);
381 AutomationTimeAxisView::clear_clicked ()
383 assert (_line || _view);
385 _session->begin_reversible_command (_("clear automation"));
393 _session->commit_reversible_command ();
394 _session->set_dirty ();
398 AutomationTimeAxisView::set_height (uint32_t h)
400 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
401 uint32_t const normal = preset_height (HeightNormal);
402 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
404 TimeAxisView* state_parent = get_parent_with_state ();
405 assert(state_parent);
406 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
408 TimeAxisView::set_height (h);
409 _base_rect->property_y2() = h;
412 _line->set_height(h);
416 _view->set_height(h);
417 _view->update_contents_height();
421 snprintf (buf, sizeof (buf), "%u", height);
423 xml_node->add_property ("height", buf);
426 if (changed_between_small_and_normal || first_call_to_set_height) {
428 first_call_to_set_height = false;
430 if (h >= preset_height (HeightNormal)) {
431 controls_table.remove (name_hbox);
434 if (plugname_packed) {
435 controls_table.remove (*plugname);
436 plugname_packed = false;
438 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
439 plugname_packed = true;
440 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
442 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
446 name_hbox.show_all ();
449 hide_button.show_all();
451 } else if (h >= preset_height (HeightSmall)) {
452 controls_table.remove (name_hbox);
454 if (plugname_packed) {
455 controls_table.remove (*plugname);
456 plugname_packed = false;
459 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
460 controls_table.hide_all ();
463 name_hbox.show_all ();
468 } else if (h >= preset_height (HeightNormal)) {
469 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
473 if (canvas_item_visible (_canvas_display)) {
474 /* only emit the signal if the height really changed and we were visible */
475 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
481 AutomationTimeAxisView::set_samples_per_unit (double spu)
483 TimeAxisView::set_samples_per_unit (spu);
490 _view->set_samples_per_unit (spu);
495 AutomationTimeAxisView::hide_clicked ()
497 // LAME fix for refreshing the hide button
498 hide_button.set_sensitive(false);
500 set_marked_for_display (false);
503 hide_button.set_sensitive(true);
507 AutomationTimeAxisView::build_display_menu ()
509 using namespace Menu_Helpers;
513 TimeAxisView::build_display_menu ();
515 /* now fill it with our stuff */
517 MenuList& items = display_menu->items();
519 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
520 items.push_back (SeparatorElem());
521 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
522 items.push_back (SeparatorElem());
526 Menu* auto_state_menu = manage (new Menu);
527 auto_state_menu->set_name ("ArdourContextMenu");
528 MenuList& as_items = auto_state_menu->items();
530 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
531 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
533 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
535 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
536 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
538 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
540 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
541 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
542 (AutoState) Write)));
543 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
545 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
546 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
547 (AutoState) Touch)));
548 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
550 items.push_back (MenuElem (_("State"), *auto_state_menu));
554 /* current interpolation state */
555 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
557 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
559 Menu* auto_mode_menu = manage (new Menu);
560 auto_mode_menu->set_name ("ArdourContextMenu");
561 MenuList& am_items = auto_mode_menu->items();
563 RadioMenuItem::Group group;
565 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
566 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
567 AutomationList::Discrete)));
568 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
569 mode_discrete_item->set_active (s == AutomationList::Discrete);
571 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
572 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
573 AutomationList::Linear)));
574 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
575 mode_line_item->set_active (s == AutomationList::Linear);
577 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
580 /* make sure the automation menu state is correct */
582 automation_state_changed ();
583 interpolation_changed (s);
587 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
594 _canvas_display->w2i (x, y);
596 /* compute vertical fractional position */
598 y = 1.0 - (y / height);
602 _line->view_to_model_coord (x, y);
604 _session->begin_reversible_command (_("add automation event"));
605 XMLNode& before = _control->alist()->get_state();
607 _control->alist()->add (when, y);
609 XMLNode& after = _control->alist()->get_state();
610 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
612 _session->set_dirty ();
616 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
618 list<boost::shared_ptr<AutomationLine> > lines;
620 lines.push_back (_line);
622 lines = _view->get_lines ();
625 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
626 cut_copy_clear_one (**i, selection, op);
631 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
633 boost::shared_ptr<Evoral::ControlList> what_we_got;
634 boost::shared_ptr<AutomationList> alist (line.the_list());
636 XMLNode &before = alist->get_state();
638 /* convert time selection to automation list model coordinates */
639 const Evoral::TimeConverter<double, ARDOUR::sframes_t>& tc = line.time_converter ();
640 double const start = tc.from (selection.time.front().start - tc.origin_b ());
641 double const end = tc.from (selection.time.front().end - tc.origin_b ());
646 if ((what_we_got = alist->cut (start, end)) != 0) {
647 _editor.get_cut_buffer().add (what_we_got);
648 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
652 if ((what_we_got = alist->copy (start, end)) != 0) {
653 _editor.get_cut_buffer().add (what_we_got);
658 if ((what_we_got = alist->cut (start, end)) != 0) {
659 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
665 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
666 double when = (*x)->when;
667 double val = (*x)->value;
668 line.model_to_view_coord (when, val);
676 AutomationTimeAxisView::reset_objects (PointSelection& selection)
678 list<boost::shared_ptr<AutomationLine> > lines;
680 lines.push_back (_line);
682 lines = _view->get_lines ();
685 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
686 reset_objects_one (**i, selection);
691 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
693 boost::shared_ptr<AutomationList> alist(line.the_list());
695 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
697 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
699 if ((*i).track != this) {
703 alist->reset_range ((*i).start, (*i).end);
708 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
710 list<boost::shared_ptr<AutomationLine> > lines;
712 lines.push_back (_line);
714 lines = _view->get_lines ();
717 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
718 cut_copy_clear_objects_one (**i, selection, op);
723 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
725 boost::shared_ptr<Evoral::ControlList> what_we_got;
726 boost::shared_ptr<AutomationList> alist(line.the_list());
728 XMLNode &before = alist->get_state();
730 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
732 if ((*i).track != this) {
738 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
739 _editor.get_cut_buffer().add (what_we_got);
740 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
744 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
745 _editor.get_cut_buffer().add (what_we_got);
750 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
751 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
760 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
761 double when = (*x)->when;
762 double val = (*x)->value;
763 line.model_to_view_coord (when, val);
770 /** Paste a selection.
771 * @param pos Position to paste to (session frames).
772 * @param times Number of times to paste.
773 * @param selection Selection to paste.
774 * @param nth Index of the AutomationList within the selection to paste from.
777 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
779 boost::shared_ptr<AutomationLine> line;
784 line = _view->paste_line (pos);
791 return paste_one (*line, pos, times, selection, nth);
795 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
797 AutomationSelection::iterator p;
798 boost::shared_ptr<AutomationList> alist(line.the_list());
800 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
802 if (p == selection.lines.end()) {
806 /* Make a copy of the list because we have to scale the
807 values from view coordinates to model coordinates, and we're
808 not supposed to modify the points in the selection.
811 AutomationList copy (**p);
813 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
814 double when = (*x)->when;
815 double val = (*x)->value;
816 line.view_to_model_coord (when, val);
821 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
823 XMLNode &before = alist->get_state();
824 alist->paste (copy, model_pos, times);
825 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
831 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
833 if (!_line && !_view) {
837 if (touched (top, bot)) {
839 /* remember: this is X Window - coordinate space starts in upper left and moves down.
840 _y_position is the "origin" or "top" of the track.
843 /* bottom of our track */
844 double const mybot = _y_position + height;
849 if (_y_position >= top && mybot <= bot) {
851 /* _y_position is below top, mybot is above bot, so we're fully
860 /* top and bot are within _y_position .. mybot */
862 topfrac = 1.0 - ((top - _y_position) / height);
863 botfrac = 1.0 - ((bot - _y_position) / height);
868 _line->get_selectables (start, end, botfrac, topfrac, results);
870 _view->get_selectables (start, end, botfrac, topfrac, results);
876 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
879 _line->get_inverted_selectables (sel, result);
884 AutomationTimeAxisView::set_selected_points (PointSelection& points)
887 _line->set_selected_points (points);
889 _view->set_selected_points (points);
894 AutomationTimeAxisView::clear_lines ()
897 _list_connections.drop_connections ();
901 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
905 assert(line->the_list() == _control->list());
907 _control->alist()->automation_state_changed.connect (
908 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
911 _control->alist()->InterpolationChanged.connect (
912 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
916 //_controller = AutomationController::create(_session, line->the_list(), _control);
918 line->set_height (height);
920 /* pick up the current state */
921 automation_state_changed ();
927 AutomationTimeAxisView::entered()
930 _line->track_entered();
934 AutomationTimeAxisView::exited ()
937 _line->track_exited();
941 AutomationTimeAxisView::color_handler ()
949 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
951 TimeAxisView::set_state (node, version);
953 XMLProperty const * type = node.property ("automation-id");
954 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
955 XMLProperty const * shown = node.property ("shown");
956 if (shown && shown->value () == "yes") {
957 set_marked_for_display (true);
958 _canvas_display->show (); /* FIXME: necessary? show_at? */
962 if (!_marked_for_display) {
970 AutomationTimeAxisView::get_state_node ()
972 TimeAxisView* state_parent = get_parent_with_state ();
975 return state_parent->get_automation_child_xml_node (_control->parameter());
982 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
984 XMLNode* xml_node = get_state_node();
986 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
991 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
993 update_extra_xml_shown (true);
995 return TimeAxisView::show_at (y, nth, parent);
999 AutomationTimeAxisView::hide ()
1001 update_extra_xml_shown (false);
1003 TimeAxisView::hide ();
1007 AutomationTimeAxisView::set_visibility (bool yn)
1009 bool changed = TimeAxisView::set_visibility (yn);
1012 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1018 /** @return true if this view has any automation data to display */
1020 AutomationTimeAxisView::has_automation () const
1022 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );