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 /** gnomecanvas sometimes converts this value to int or adds 2 to it, so it must be
96 set correctly to avoid overflow.
98 _base_rect->property_x2() = INT_MAX - 2;
99 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
101 /* outline ends and bottom */
102 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
103 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
105 _base_rect->set_data ("trackview", this);
107 _base_rect->signal_event().connect (sigc::bind (
108 sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
112 _base_rect->lower_to_bottom();
115 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
117 auto_button.set_name ("TrackVisualButton");
118 hide_button.set_name ("TrackRemoveButton");
120 auto_button.unset_flags (Gtk::CAN_FOCUS);
121 hide_button.unset_flags (Gtk::CAN_FOCUS);
123 controls_table.set_no_show_all();
125 ARDOUR_UI::instance()->set_tip(auto_button, _("automation state"));
126 ARDOUR_UI::instance()->set_tip(hide_button, _("hide track"));
128 /* rearrange the name display */
130 /* we never show these for automation tracks, so make
131 life easier and remove them.
136 /* move the name label over a bit */
138 string shortpname = _name;
139 bool shortened = false;
142 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
144 if (shortpname != _name ){
148 name_label.set_text (shortpname);
149 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
151 if (nomparent.length()) {
153 /* limit the plug name string */
155 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
156 if (pname != nomparent) {
160 plugname = new Label (pname);
161 plugname->set_name (X_("TrackPlugName"));
163 name_label.set_name (X_("TrackParameterName"));
164 controls_table.remove (name_hbox);
165 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
166 plugname_packed = true;
167 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
170 plugname_packed = false;
174 string tipname = nomparent;
175 if (!tipname.empty()) {
179 ARDOUR_UI::instance()->set_tip(controls_ebox, tipname);
182 /* add the buttons */
183 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
185 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
187 /* add bar controller */
188 controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
190 controls_table.show_all ();
192 hide_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
193 auto_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
195 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
196 controls_base_unselected_name = X_("AutomationTrackControlsBase");
197 controls_ebox.set_name (controls_base_unselected_name);
199 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (_control->parameter());
202 set_state (*xml_node, Stateful::loading_state_version);
205 /* ask for notifications of any new RegionViews */
211 /* no regions, just a single line for the entire track (e.g. bus gain) */
213 boost::shared_ptr<AutomationLine> line(new AutomationLine (
214 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
219 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
220 line->queue_reset ();
224 /* make sure labels etc. are correct */
226 automation_state_changed ();
227 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
230 AutomationTimeAxisView::~AutomationTimeAxisView ()
235 AutomationTimeAxisView::auto_clicked ()
237 using namespace Menu_Helpers;
239 if (automation_menu == 0) {
240 automation_menu = manage (new Menu);
241 automation_menu->set_name ("ArdourContextMenu");
242 MenuList& items (automation_menu->items());
244 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
245 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
246 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
247 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
248 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
249 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
250 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
251 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
254 automation_menu->popup (1, gtk_get_current_event_time());
258 AutomationTimeAxisView::set_automation_state (AutoState state)
260 if (ignore_state_request) {
265 _automatable->set_parameter_automation_state (_control->parameter(), state);
268 if (_route == _automatable) { // This is a time axis for route (not region) automation
269 _route->set_parameter_automation_state (_control->parameter(), state);
272 if (_control->list()) {
273 _control->alist()->set_automation_state(state);
277 _view->set_automation_state (state);
279 /* AutomationStreamViews don't signal when their automation state changes, so handle
280 our updates `manually'.
282 automation_state_changed ();
287 AutomationTimeAxisView::automation_state_changed ()
291 /* update button label */
294 state = _control->alist()->automation_state ();
296 state = _view->automation_state ();
301 switch (state & (Off|Play|Touch|Write)) {
303 auto_button.set_label (_("Manual"));
305 ignore_state_request = true;
306 auto_off_item->set_active (true);
307 auto_play_item->set_active (false);
308 auto_touch_item->set_active (false);
309 auto_write_item->set_active (false);
310 ignore_state_request = false;
314 auto_button.set_label (_("Play"));
315 if (auto_play_item) {
316 ignore_state_request = true;
317 auto_play_item->set_active (true);
318 auto_off_item->set_active (false);
319 auto_touch_item->set_active (false);
320 auto_write_item->set_active (false);
321 ignore_state_request = false;
325 auto_button.set_label (_("Write"));
326 if (auto_write_item) {
327 ignore_state_request = true;
328 auto_write_item->set_active (true);
329 auto_off_item->set_active (false);
330 auto_play_item->set_active (false);
331 auto_touch_item->set_active (false);
332 ignore_state_request = false;
336 auto_button.set_label (_("Touch"));
337 if (auto_touch_item) {
338 ignore_state_request = true;
339 auto_touch_item->set_active (true);
340 auto_off_item->set_active (false);
341 auto_play_item->set_active (false);
342 auto_write_item->set_active (false);
343 ignore_state_request = false;
347 auto_button.set_label (_("???"));
352 /** The interpolation style of our AutomationList has changed, so update */
354 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
356 if (mode_line_item && mode_discrete_item) {
357 if (s == AutomationList::Discrete) {
358 mode_discrete_item->set_active(true);
359 mode_line_item->set_active(false);
361 mode_line_item->set_active(true);
362 mode_discrete_item->set_active(false);
367 /** A menu item has been selected to change our interpolation mode */
369 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
371 /* Tell our view's list, if we have one, otherwise tell our own.
372 * Everything else will be signalled back from that.
376 _view->set_interpolation (style);
378 _control->list()->set_interpolation (style);
383 AutomationTimeAxisView::clear_clicked ()
385 assert (_line || _view);
387 _session->begin_reversible_command (_("clear automation"));
395 _session->commit_reversible_command ();
396 _session->set_dirty ();
400 AutomationTimeAxisView::set_height (uint32_t h)
402 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
403 uint32_t const normal = preset_height (HeightNormal);
404 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
406 TimeAxisView* state_parent = get_parent_with_state ();
407 assert(state_parent);
408 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
410 TimeAxisView::set_height (h);
411 _base_rect->property_y2() = h;
414 _line->set_height(h);
418 _view->set_height(h);
419 _view->update_contents_height();
423 snprintf (buf, sizeof (buf), "%u", height);
425 xml_node->add_property ("height", buf);
428 if (changed_between_small_and_normal || first_call_to_set_height) {
430 first_call_to_set_height = false;
432 if (h >= preset_height (HeightNormal)) {
433 controls_table.remove (name_hbox);
436 if (plugname_packed) {
437 controls_table.remove (*plugname);
438 plugname_packed = false;
440 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
441 plugname_packed = true;
442 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
444 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
448 name_hbox.show_all ();
451 hide_button.show_all();
453 } else if (h >= preset_height (HeightSmall)) {
454 controls_table.remove (name_hbox);
456 if (plugname_packed) {
457 controls_table.remove (*plugname);
458 plugname_packed = false;
461 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
462 controls_table.hide_all ();
465 name_hbox.show_all ();
470 } else if (h >= preset_height (HeightNormal)) {
471 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
475 if (canvas_item_visible (_canvas_display)) {
476 /* only emit the signal if the height really changed and we were visible */
477 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
483 AutomationTimeAxisView::set_samples_per_unit (double spu)
485 TimeAxisView::set_samples_per_unit (spu);
492 _view->set_samples_per_unit (spu);
497 AutomationTimeAxisView::hide_clicked ()
499 // LAME fix for refreshing the hide button
500 hide_button.set_sensitive(false);
502 set_marked_for_display (false);
505 hide_button.set_sensitive(true);
509 AutomationTimeAxisView::build_display_menu ()
511 using namespace Menu_Helpers;
515 TimeAxisView::build_display_menu ();
517 /* now fill it with our stuff */
519 MenuList& items = display_menu->items();
521 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
522 items.push_back (SeparatorElem());
523 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
524 items.push_back (SeparatorElem());
528 Menu* auto_state_menu = manage (new Menu);
529 auto_state_menu->set_name ("ArdourContextMenu");
530 MenuList& as_items = auto_state_menu->items();
532 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
533 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
535 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
537 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
538 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
540 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
542 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
543 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
544 (AutoState) Write)));
545 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
547 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
548 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
549 (AutoState) Touch)));
550 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
552 items.push_back (MenuElem (_("State"), *auto_state_menu));
556 /* current interpolation state */
557 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
559 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
561 Menu* auto_mode_menu = manage (new Menu);
562 auto_mode_menu->set_name ("ArdourContextMenu");
563 MenuList& am_items = auto_mode_menu->items();
565 RadioMenuItem::Group group;
567 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
568 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
569 AutomationList::Discrete)));
570 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
571 mode_discrete_item->set_active (s == AutomationList::Discrete);
573 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
574 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
575 AutomationList::Linear)));
576 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
577 mode_line_item->set_active (s == AutomationList::Linear);
579 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
582 /* make sure the automation menu state is correct */
584 automation_state_changed ();
585 interpolation_changed (s);
589 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, nframes_t when, double y)
596 _canvas_display->w2i (x, y);
598 /* compute vertical fractional position */
600 y = 1.0 - (y / height);
604 _line->view_to_model_coord (x, y);
606 _session->begin_reversible_command (_("add automation event"));
607 XMLNode& before = _control->alist()->get_state();
609 _control->alist()->add (when, y);
611 XMLNode& after = _control->alist()->get_state();
612 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
614 _session->set_dirty ();
618 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
620 list<boost::shared_ptr<AutomationLine> > lines;
622 lines.push_back (_line);
624 lines = _view->get_lines ();
627 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
628 cut_copy_clear_one (**i, selection, op);
633 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
635 boost::shared_ptr<Evoral::ControlList> what_we_got;
636 boost::shared_ptr<AutomationList> alist (line.the_list());
638 XMLNode &before = alist->get_state();
640 /* convert time selection to automation list model coordinates */
641 const Evoral::TimeConverter<double, ARDOUR::framepos_t>& tc = line.time_converter ();
642 double const start = tc.from (selection.time.front().start - tc.origin_b ());
643 double const end = tc.from (selection.time.front().end - tc.origin_b ());
648 if ((what_we_got = alist->cut (start, end)) != 0) {
649 _editor.get_cut_buffer().add (what_we_got);
650 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
654 if ((what_we_got = alist->copy (start, end)) != 0) {
655 _editor.get_cut_buffer().add (what_we_got);
660 if ((what_we_got = alist->cut (start, end)) != 0) {
661 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
667 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
668 double when = (*x)->when;
669 double val = (*x)->value;
670 line.model_to_view_coord (when, val);
678 AutomationTimeAxisView::reset_objects (PointSelection& selection)
680 list<boost::shared_ptr<AutomationLine> > lines;
682 lines.push_back (_line);
684 lines = _view->get_lines ();
687 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
688 reset_objects_one (**i, selection);
693 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
695 boost::shared_ptr<AutomationList> alist(line.the_list());
697 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
699 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
701 if ((*i).track != this) {
705 alist->reset_range ((*i).start, (*i).end);
710 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
712 list<boost::shared_ptr<AutomationLine> > lines;
714 lines.push_back (_line);
716 lines = _view->get_lines ();
719 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
720 cut_copy_clear_objects_one (**i, selection, op);
725 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
727 boost::shared_ptr<Evoral::ControlList> what_we_got;
728 boost::shared_ptr<AutomationList> alist(line.the_list());
730 XMLNode &before = alist->get_state();
732 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
734 if ((*i).track != this) {
740 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
741 _editor.get_cut_buffer().add (what_we_got);
742 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
746 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
747 _editor.get_cut_buffer().add (what_we_got);
752 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
753 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
762 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
763 double when = (*x)->when;
764 double val = (*x)->value;
765 line.model_to_view_coord (when, val);
772 /** Paste a selection.
773 * @param pos Position to paste to (session frames).
774 * @param times Number of times to paste.
775 * @param selection Selection to paste.
776 * @param nth Index of the AutomationList within the selection to paste from.
779 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
781 boost::shared_ptr<AutomationLine> line;
786 line = _view->paste_line (pos);
793 return paste_one (*line, pos, times, selection, nth);
797 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
799 AutomationSelection::iterator p;
800 boost::shared_ptr<AutomationList> alist(line.the_list());
802 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
804 if (p == selection.lines.end()) {
808 /* Make a copy of the list because we have to scale the
809 values from view coordinates to model coordinates, and we're
810 not supposed to modify the points in the selection.
813 AutomationList copy (**p);
815 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
816 double when = (*x)->when;
817 double val = (*x)->value;
818 line.view_to_model_coord (when, val);
823 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
825 XMLNode &before = alist->get_state();
826 alist->paste (copy, model_pos, times);
827 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
833 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
835 if (!_line && !_view) {
839 if (touched (top, bot)) {
841 /* remember: this is X Window - coordinate space starts in upper left and moves down.
842 _y_position is the "origin" or "top" of the track.
845 /* bottom of our track */
846 double const mybot = _y_position + height;
851 if (_y_position >= top && mybot <= bot) {
853 /* _y_position is below top, mybot is above bot, so we're fully
862 /* top and bot are within _y_position .. mybot */
864 topfrac = 1.0 - ((top - _y_position) / height);
865 botfrac = 1.0 - ((bot - _y_position) / height);
870 _line->get_selectables (start, end, botfrac, topfrac, results);
872 _view->get_selectables (start, end, botfrac, topfrac, results);
878 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
881 _line->get_inverted_selectables (sel, result);
886 AutomationTimeAxisView::set_selected_points (PointSelection& points)
889 _line->set_selected_points (points);
891 _view->set_selected_points (points);
896 AutomationTimeAxisView::clear_lines ()
899 _list_connections.drop_connections ();
903 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
907 assert(line->the_list() == _control->list());
909 _control->alist()->automation_state_changed.connect (
910 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
913 _control->alist()->InterpolationChanged.connect (
914 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
918 //_controller = AutomationController::create(_session, line->the_list(), _control);
920 line->set_height (height);
922 /* pick up the current state */
923 automation_state_changed ();
929 AutomationTimeAxisView::entered()
932 _line->track_entered();
936 AutomationTimeAxisView::exited ()
939 _line->track_exited();
943 AutomationTimeAxisView::color_handler ()
951 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
953 TimeAxisView::set_state (node, version);
955 if (version < 3000) {
956 return set_state_2X (node, version);
959 XMLProperty const * type = node.property ("automation-id");
960 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
961 XMLProperty const * shown = node.property ("shown");
962 if (shown && shown->value () == "yes") {
963 set_marked_for_display (true);
964 _canvas_display->show (); /* FIXME: necessary? show_at? */
968 if (!_marked_for_display) {
977 AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/)
979 if (node.name() == X_("gain") && _control->parameter() == Evoral::Parameter (GainAutomation)) {
980 XMLProperty const * shown = node.property (X_("shown"));
981 if (shown && string_is_affirmative (shown->value ())) {
982 set_marked_for_display (true);
983 _canvas_display->show (); /* FIXME: necessary? show_at? */
987 if (!_marked_for_display) {
995 AutomationTimeAxisView::get_state_node ()
997 TimeAxisView* state_parent = get_parent_with_state ();
1000 return state_parent->get_automation_child_xml_node (_control->parameter());
1007 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
1009 XMLNode* xml_node = get_state_node();
1011 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
1016 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
1018 update_extra_xml_shown (true);
1020 return TimeAxisView::show_at (y, nth, parent);
1024 AutomationTimeAxisView::hide ()
1026 update_extra_xml_shown (false);
1028 TimeAxisView::hide ();
1032 AutomationTimeAxisView::set_visibility (bool yn)
1034 bool changed = TimeAxisView::set_visibility (yn);
1037 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1043 /** @return true if this view has any automation data to display */
1045 AutomationTimeAxisView::has_automation () const
1047 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );
1050 list<boost::shared_ptr<AutomationLine> >
1051 AutomationTimeAxisView::lines () const
1053 list<boost::shared_ptr<AutomationLine> > lines;
1056 lines.push_back (_line);
1058 lines = _view->get_lines ();