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 (_control->parameter());
199 set_state (*xml_node, Stateful::loading_state_version);
202 /* ask for notifications of any new RegionViews */
208 /* no regions, just a single line for the entire track (e.g. bus gain) */
210 boost::shared_ptr<AutomationLine> line(new AutomationLine (
211 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
216 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
217 line->queue_reset ();
221 /* make sure labels etc. are correct */
223 automation_state_changed ();
224 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
227 AutomationTimeAxisView::~AutomationTimeAxisView ()
232 AutomationTimeAxisView::auto_clicked ()
234 using namespace Menu_Helpers;
236 if (automation_menu == 0) {
237 automation_menu = manage (new Menu);
238 automation_menu->set_name ("ArdourContextMenu");
239 MenuList& items (automation_menu->items());
241 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
242 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
243 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
244 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
245 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
246 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
247 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
248 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
251 automation_menu->popup (1, gtk_get_current_event_time());
255 AutomationTimeAxisView::set_automation_state (AutoState state)
257 if (ignore_state_request) {
262 _automatable->set_parameter_automation_state (_control->parameter(), state);
265 if (_route == _automatable) { // This is a time axis for route (not region) automation
266 _route->set_parameter_automation_state (_control->parameter(), state);
269 if (_control->list()) {
270 _control->alist()->set_automation_state(state);
274 _view->set_automation_state (state);
276 /* AutomationStreamViews don't signal when their automation state changes, so handle
277 our updates `manually'.
279 automation_state_changed ();
284 AutomationTimeAxisView::automation_state_changed ()
288 /* update button label */
291 state = _control->alist()->automation_state ();
293 state = _view->automation_state ();
298 switch (state & (Off|Play|Touch|Write)) {
300 auto_button.set_label (_("Manual"));
302 ignore_state_request = true;
303 auto_off_item->set_active (true);
304 auto_play_item->set_active (false);
305 auto_touch_item->set_active (false);
306 auto_write_item->set_active (false);
307 ignore_state_request = false;
311 auto_button.set_label (_("Play"));
312 if (auto_play_item) {
313 ignore_state_request = true;
314 auto_play_item->set_active (true);
315 auto_off_item->set_active (false);
316 auto_touch_item->set_active (false);
317 auto_write_item->set_active (false);
318 ignore_state_request = false;
322 auto_button.set_label (_("Write"));
323 if (auto_write_item) {
324 ignore_state_request = true;
325 auto_write_item->set_active (true);
326 auto_off_item->set_active (false);
327 auto_play_item->set_active (false);
328 auto_touch_item->set_active (false);
329 ignore_state_request = false;
333 auto_button.set_label (_("Touch"));
334 if (auto_touch_item) {
335 ignore_state_request = true;
336 auto_touch_item->set_active (true);
337 auto_off_item->set_active (false);
338 auto_play_item->set_active (false);
339 auto_write_item->set_active (false);
340 ignore_state_request = false;
344 auto_button.set_label (_("???"));
349 /** The interpolation style of our AutomationList has changed, so update */
351 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
353 if (mode_line_item && mode_discrete_item) {
354 if (s == AutomationList::Discrete) {
355 mode_discrete_item->set_active(true);
356 mode_line_item->set_active(false);
358 mode_line_item->set_active(true);
359 mode_discrete_item->set_active(false);
364 /** A menu item has been selected to change our interpolation mode */
366 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
368 /* Tell our view's list, if we have one, otherwise tell our own.
369 * Everything else will be signalled back from that.
373 _view->set_interpolation (style);
375 _control->list()->set_interpolation (style);
380 AutomationTimeAxisView::clear_clicked ()
382 assert (_line || _view);
384 _session->begin_reversible_command (_("clear automation"));
392 _session->commit_reversible_command ();
393 _session->set_dirty ();
397 AutomationTimeAxisView::set_height (uint32_t h)
399 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
400 uint32_t const normal = preset_height (HeightNormal);
401 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
403 TimeAxisView* state_parent = get_parent_with_state ();
404 assert(state_parent);
405 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
407 TimeAxisView::set_height (h);
408 _base_rect->property_y2() = h;
411 _line->set_height(h);
415 _view->set_height(h);
416 _view->update_contents_height();
420 snprintf (buf, sizeof (buf), "%u", height);
422 xml_node->add_property ("height", buf);
425 if (changed_between_small_and_normal || first_call_to_set_height) {
427 first_call_to_set_height = false;
429 if (h >= preset_height (HeightNormal)) {
430 controls_table.remove (name_hbox);
433 if (plugname_packed) {
434 controls_table.remove (*plugname);
435 plugname_packed = false;
437 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
438 plugname_packed = true;
439 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
441 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
445 name_hbox.show_all ();
448 hide_button.show_all();
450 } else if (h >= preset_height (HeightSmall)) {
451 controls_table.remove (name_hbox);
453 if (plugname_packed) {
454 controls_table.remove (*plugname);
455 plugname_packed = false;
458 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
459 controls_table.hide_all ();
462 name_hbox.show_all ();
467 } else if (h >= preset_height (HeightNormal)) {
468 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
472 if (canvas_item_visible (_canvas_display)) {
473 /* only emit the signal if the height really changed and we were visible */
474 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
480 AutomationTimeAxisView::set_samples_per_unit (double spu)
482 TimeAxisView::set_samples_per_unit (spu);
489 _view->set_samples_per_unit (spu);
494 AutomationTimeAxisView::hide_clicked ()
496 // LAME fix for refreshing the hide button
497 hide_button.set_sensitive(false);
499 set_marked_for_display (false);
502 hide_button.set_sensitive(true);
506 AutomationTimeAxisView::build_display_menu ()
508 using namespace Menu_Helpers;
512 TimeAxisView::build_display_menu ();
514 /* now fill it with our stuff */
516 MenuList& items = display_menu->items();
518 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
519 items.push_back (SeparatorElem());
520 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
521 items.push_back (SeparatorElem());
525 Menu* auto_state_menu = manage (new Menu);
526 auto_state_menu->set_name ("ArdourContextMenu");
527 MenuList& as_items = auto_state_menu->items();
529 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
530 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
532 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
534 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
535 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
537 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
539 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
540 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
541 (AutoState) Write)));
542 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
544 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
545 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
546 (AutoState) Touch)));
547 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
549 items.push_back (MenuElem (_("State"), *auto_state_menu));
553 /* current interpolation state */
554 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
556 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
558 Menu* auto_mode_menu = manage (new Menu);
559 auto_mode_menu->set_name ("ArdourContextMenu");
560 MenuList& am_items = auto_mode_menu->items();
562 RadioMenuItem::Group group;
564 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
565 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
566 AutomationList::Discrete)));
567 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
568 mode_discrete_item->set_active (s == AutomationList::Discrete);
570 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
571 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
572 AutomationList::Linear)));
573 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
574 mode_line_item->set_active (s == AutomationList::Linear);
576 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
579 /* make sure the automation menu state is correct */
581 automation_state_changed ();
582 interpolation_changed (s);
586 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
593 _canvas_display->w2i (x, y);
595 /* compute vertical fractional position */
597 y = 1.0 - (y / height);
601 _line->view_to_model_coord (x, y);
603 _session->begin_reversible_command (_("add automation event"));
604 XMLNode& before = _control->alist()->get_state();
606 _control->alist()->add (when, y);
608 XMLNode& after = _control->alist()->get_state();
609 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
611 _session->set_dirty ();
615 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
617 list<boost::shared_ptr<AutomationLine> > lines;
619 lines.push_back (_line);
621 lines = _view->get_lines ();
624 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
625 cut_copy_clear_one (**i, selection, op);
630 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
632 boost::shared_ptr<Evoral::ControlList> what_we_got;
633 boost::shared_ptr<AutomationList> alist (line.the_list());
635 XMLNode &before = alist->get_state();
637 /* convert time selection to automation list model coordinates */
638 const Evoral::TimeConverter<double, ARDOUR::framepos_t>& tc = line.time_converter ();
639 double const start = tc.from (selection.time.front().start - tc.origin_b ());
640 double const end = tc.from (selection.time.front().end - tc.origin_b ());
645 if ((what_we_got = alist->cut (start, end)) != 0) {
646 _editor.get_cut_buffer().add (what_we_got);
647 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
651 if ((what_we_got = alist->copy (start, end)) != 0) {
652 _editor.get_cut_buffer().add (what_we_got);
657 if ((what_we_got = alist->cut (start, end)) != 0) {
658 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
664 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
665 double when = (*x)->when;
666 double val = (*x)->value;
667 line.model_to_view_coord (when, val);
675 AutomationTimeAxisView::reset_objects (PointSelection& selection)
677 list<boost::shared_ptr<AutomationLine> > lines;
679 lines.push_back (_line);
681 lines = _view->get_lines ();
684 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
685 reset_objects_one (**i, selection);
690 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
692 boost::shared_ptr<AutomationList> alist(line.the_list());
694 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
696 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
698 if ((*i).track != this) {
702 alist->reset_range ((*i).start, (*i).end);
707 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
709 list<boost::shared_ptr<AutomationLine> > lines;
711 lines.push_back (_line);
713 lines = _view->get_lines ();
716 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
717 cut_copy_clear_objects_one (**i, selection, op);
722 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
724 boost::shared_ptr<Evoral::ControlList> what_we_got;
725 boost::shared_ptr<AutomationList> alist(line.the_list());
727 XMLNode &before = alist->get_state();
729 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
731 if ((*i).track != this) {
737 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
738 _editor.get_cut_buffer().add (what_we_got);
739 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
743 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
744 _editor.get_cut_buffer().add (what_we_got);
749 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
750 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
759 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
760 double when = (*x)->when;
761 double val = (*x)->value;
762 line.model_to_view_coord (when, val);
769 /** Paste a selection.
770 * @param pos Position to paste to (session frames).
771 * @param times Number of times to paste.
772 * @param selection Selection to paste.
773 * @param nth Index of the AutomationList within the selection to paste from.
776 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
778 boost::shared_ptr<AutomationLine> line;
783 line = _view->paste_line (pos);
790 return paste_one (*line, pos, times, selection, nth);
794 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
796 AutomationSelection::iterator p;
797 boost::shared_ptr<AutomationList> alist(line.the_list());
799 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
801 if (p == selection.lines.end()) {
805 /* Make a copy of the list because we have to scale the
806 values from view coordinates to model coordinates, and we're
807 not supposed to modify the points in the selection.
810 AutomationList copy (**p);
812 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
813 double when = (*x)->when;
814 double val = (*x)->value;
815 line.view_to_model_coord (when, val);
820 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
822 XMLNode &before = alist->get_state();
823 alist->paste (copy, model_pos, times);
824 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
830 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
832 if (!_line && !_view) {
836 if (touched (top, bot)) {
838 /* remember: this is X Window - coordinate space starts in upper left and moves down.
839 _y_position is the "origin" or "top" of the track.
842 /* bottom of our track */
843 double const mybot = _y_position + height;
848 if (_y_position >= top && mybot <= bot) {
850 /* _y_position is below top, mybot is above bot, so we're fully
859 /* top and bot are within _y_position .. mybot */
861 topfrac = 1.0 - ((top - _y_position) / height);
862 botfrac = 1.0 - ((bot - _y_position) / height);
867 _line->get_selectables (start, end, botfrac, topfrac, results);
869 _view->get_selectables (start, end, botfrac, topfrac, results);
875 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
878 _line->get_inverted_selectables (sel, result);
883 AutomationTimeAxisView::set_selected_points (PointSelection& points)
886 _line->set_selected_points (points);
888 _view->set_selected_points (points);
893 AutomationTimeAxisView::clear_lines ()
896 _list_connections.drop_connections ();
900 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
904 assert(line->the_list() == _control->list());
906 _control->alist()->automation_state_changed.connect (
907 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
910 _control->alist()->InterpolationChanged.connect (
911 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
915 //_controller = AutomationController::create(_session, line->the_list(), _control);
917 line->set_height (height);
919 /* pick up the current state */
920 automation_state_changed ();
926 AutomationTimeAxisView::entered()
929 _line->track_entered();
933 AutomationTimeAxisView::exited ()
936 _line->track_exited();
940 AutomationTimeAxisView::color_handler ()
948 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
950 TimeAxisView::set_state (node, version);
952 if (version < 3000) {
953 return set_state_2X (node, version);
956 XMLProperty const * type = node.property ("automation-id");
957 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
958 XMLProperty const * shown = node.property ("shown");
959 if (shown && shown->value () == "yes") {
960 set_marked_for_display (true);
961 _canvas_display->show (); /* FIXME: necessary? show_at? */
965 if (!_marked_for_display) {
973 AutomationTimeAxisView::set_state_2X (const XMLNode& node, int version)
975 if (node.name() == X_("gain") && _control->parameter() == Evoral::Parameter (GainAutomation)) {
976 XMLProperty const * shown = node.property (X_("shown"));
977 if (shown && string_is_affirmative (shown->value ())) {
978 set_marked_for_display (true);
979 _canvas_display->show (); /* FIXME: necessary? show_at? */
983 if (!_marked_for_display) {
991 AutomationTimeAxisView::get_state_node ()
993 TimeAxisView* state_parent = get_parent_with_state ();
996 return state_parent->get_automation_child_xml_node (_control->parameter());
1003 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
1005 XMLNode* xml_node = get_state_node();
1007 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
1012 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
1014 update_extra_xml_shown (true);
1016 return TimeAxisView::show_at (y, nth, parent);
1020 AutomationTimeAxisView::hide ()
1022 update_extra_xml_shown (false);
1024 TimeAxisView::hide ();
1028 AutomationTimeAxisView::set_visibility (bool yn)
1030 bool changed = TimeAxisView::set_visibility (yn);
1033 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1039 /** @return true if this view has any automation data to display */
1041 AutomationTimeAxisView::has_automation () const
1043 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );
1046 list<boost::shared_ptr<AutomationLine> >
1047 AutomationTimeAxisView::lines () const
1049 list<boost::shared_ptr<AutomationLine> > lines;
1052 lines.push_back (_line);
1054 lines = _view->get_lines ();