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 "global_signals.h"
32 #include "gui_thread.h"
33 #include "route_time_axis.h"
34 #include "automation_line.h"
35 #include "public_editor.h"
36 #include "simplerect.h"
37 #include "selection.h"
38 #include "rgb_macros.h"
39 #include "point_selection.h"
40 #include "canvas_impl.h"
46 using namespace ARDOUR;
49 using namespace Gtkmm2ext;
50 using namespace Editing;
52 Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
53 bool AutomationTimeAxisView::have_name_font = false;
54 const string AutomationTimeAxisView::state_node_name = "AutomationChild";
57 /** \a a the automatable object this time axis is to display data for.
58 * For route/track automation (e.g. gain) pass the route for both \r and \a.
59 * For route child (e.g. plugin) automation, pass the child for \a.
60 * For region automation (e.g. MIDI CC), pass null for \a.
62 AutomationTimeAxisView::AutomationTimeAxisView (
64 boost::shared_ptr<Route> r,
65 boost::shared_ptr<Automatable> a,
66 boost::shared_ptr<AutomationControl> c,
70 ArdourCanvas::Canvas& canvas,
72 const string & nomparent
75 , TimeAxisView (s, e, &parent, canvas)
79 , _controller (AutomationController::create (a, c->parameter(), c))
81 , _view (show_regions ? new AutomationStreamView (*this) : 0)
83 , auto_button (X_("")) /* force addition of a label */
85 if (!have_name_font) {
86 name_font = get_font_for_style (X_("AutomationTrackName"));
87 have_name_font = true;
95 mode_discrete_item = 0;
98 ignore_state_request = false;
99 first_call_to_set_height = true;
101 _base_rect = new SimpleRect(*_canvas_display);
102 _base_rect->property_x1() = 0.0;
103 _base_rect->property_y1() = 0.0;
104 /** gnomecanvas sometimes converts this value to int or adds 2 to it, so it must be
105 set correctly to avoid overflow.
107 _base_rect->property_x2() = INT_MAX - 2;
108 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
110 /* outline ends and bottom */
111 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
112 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
114 _base_rect->set_data ("trackview", this);
116 _base_rect->signal_event().connect (sigc::bind (
117 sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
121 _base_rect->lower_to_bottom();
124 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
126 auto_button.set_name ("TrackVisualButton");
127 hide_button.set_name ("TrackRemoveButton");
129 auto_button.unset_flags (Gtk::CAN_FOCUS);
130 hide_button.unset_flags (Gtk::CAN_FOCUS);
132 controls_table.set_no_show_all();
134 ARDOUR_UI::instance()->set_tip(auto_button, _("automation state"));
135 ARDOUR_UI::instance()->set_tip(hide_button, _("hide track"));
137 /* rearrange the name display */
139 /* we never show these for automation tracks, so make
140 life easier and remove them.
145 /* move the name label over a bit */
147 string shortpname = _name;
148 bool shortened = false;
151 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
153 if (shortpname != _name ){
157 name_label.set_text (shortpname);
158 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
159 name_label.set_name (X_("TrackParameterName"));
161 if (nomparent.length()) {
163 /* limit the plug name string */
165 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
166 if (pname != nomparent) {
170 plugname = new Label (pname);
171 plugname->set_name (X_("TrackPlugName"));
173 controls_table.remove (name_hbox);
174 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
175 plugname_packed = true;
176 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
179 plugname_packed = false;
183 string tipname = nomparent;
184 if (!tipname.empty()) {
188 ARDOUR_UI::instance()->set_tip(controls_ebox, tipname);
191 /* add the buttons */
192 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
194 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
196 /* add bar controller */
197 controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
199 controls_table.show_all ();
201 hide_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
202 auto_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
204 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
205 controls_base_unselected_name = X_("AutomationTrackControlsBase");
206 controls_ebox.set_name (controls_base_unselected_name);
208 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (_control->parameter());
211 set_state (*xml_node, Stateful::loading_state_version);
214 /* ask for notifications of any new RegionViews */
221 /* no regions, just a single line for the entire track (e.g. bus gain) */
223 boost::shared_ptr<AutomationLine> line (
225 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
232 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
233 line->queue_reset ();
237 /* make sure labels etc. are correct */
239 automation_state_changed ();
240 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
243 AutomationTimeAxisView::~AutomationTimeAxisView ()
248 AutomationTimeAxisView::auto_clicked ()
250 using namespace Menu_Helpers;
252 if (automation_menu == 0) {
253 automation_menu = manage (new Menu);
254 automation_menu->set_name ("ArdourContextMenu");
255 MenuList& items (automation_menu->items());
257 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
258 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
259 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
260 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
261 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
262 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
263 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
264 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
267 automation_menu->popup (1, gtk_get_current_event_time());
271 AutomationTimeAxisView::set_automation_state (AutoState state)
273 if (ignore_state_request) {
278 _automatable->set_parameter_automation_state (_control->parameter(), state);
281 if (_route == _automatable) { // This is a time axis for route (not region) automation
282 _route->set_parameter_automation_state (_control->parameter(), state);
285 if (_control->list()) {
286 _control->alist()->set_automation_state(state);
290 _view->set_automation_state (state);
292 /* AutomationStreamViews don't signal when their automation state changes, so handle
293 our updates `manually'.
295 automation_state_changed ();
300 AutomationTimeAxisView::automation_state_changed ()
304 /* update button label */
307 state = _control->alist()->automation_state ();
309 state = _view->automation_state ();
314 switch (state & (Off|Play|Touch|Write)) {
316 auto_button.set_label (_("Manual"));
318 ignore_state_request = true;
319 auto_off_item->set_active (true);
320 auto_play_item->set_active (false);
321 auto_touch_item->set_active (false);
322 auto_write_item->set_active (false);
323 ignore_state_request = false;
327 auto_button.set_label (_("Play"));
328 if (auto_play_item) {
329 ignore_state_request = true;
330 auto_play_item->set_active (true);
331 auto_off_item->set_active (false);
332 auto_touch_item->set_active (false);
333 auto_write_item->set_active (false);
334 ignore_state_request = false;
338 auto_button.set_label (_("Write"));
339 if (auto_write_item) {
340 ignore_state_request = true;
341 auto_write_item->set_active (true);
342 auto_off_item->set_active (false);
343 auto_play_item->set_active (false);
344 auto_touch_item->set_active (false);
345 ignore_state_request = false;
349 auto_button.set_label (_("Touch"));
350 if (auto_touch_item) {
351 ignore_state_request = true;
352 auto_touch_item->set_active (true);
353 auto_off_item->set_active (false);
354 auto_play_item->set_active (false);
355 auto_write_item->set_active (false);
356 ignore_state_request = false;
360 auto_button.set_label (_("???"));
365 /** The interpolation style of our AutomationList has changed, so update */
367 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
369 if (mode_line_item && mode_discrete_item) {
370 if (s == AutomationList::Discrete) {
371 mode_discrete_item->set_active(true);
372 mode_line_item->set_active(false);
374 mode_line_item->set_active(true);
375 mode_discrete_item->set_active(false);
380 /** A menu item has been selected to change our interpolation mode */
382 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
384 /* Tell our view's list, if we have one, otherwise tell our own.
385 * Everything else will be signalled back from that.
389 _view->set_interpolation (style);
391 _control->list()->set_interpolation (style);
396 AutomationTimeAxisView::clear_clicked ()
398 assert (_line || _view);
400 _session->begin_reversible_command (_("clear automation"));
408 _session->commit_reversible_command ();
409 _session->set_dirty ();
413 AutomationTimeAxisView::set_height (uint32_t h)
415 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
416 uint32_t const normal = preset_height (HeightNormal);
417 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
419 TimeAxisView* state_parent = get_parent_with_state ();
420 assert(state_parent);
421 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
423 TimeAxisView::set_height (h);
424 _base_rect->property_y2() = h;
427 _line->set_height(h);
431 _view->set_height(h);
432 _view->update_contents_height();
436 snprintf (buf, sizeof (buf), "%u", height);
438 xml_node->add_property ("height", buf);
441 if (changed_between_small_and_normal || first_call_to_set_height) {
443 first_call_to_set_height = false;
445 if (h >= preset_height (HeightNormal)) {
446 controls_table.remove (name_hbox);
449 if (plugname_packed) {
450 controls_table.remove (*plugname);
451 plugname_packed = false;
453 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
454 plugname_packed = true;
455 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
457 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
461 name_hbox.show_all ();
464 hide_button.show_all();
466 } else if (h >= preset_height (HeightSmall)) {
467 controls_table.remove (name_hbox);
469 if (plugname_packed) {
470 controls_table.remove (*plugname);
471 plugname_packed = false;
474 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
475 controls_table.hide_all ();
478 name_hbox.show_all ();
483 } else if (h >= preset_height (HeightNormal)) {
484 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
488 if (canvas_item_visible (_canvas_display)) {
489 /* only emit the signal if the height really changed and we were visible */
490 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
496 AutomationTimeAxisView::set_samples_per_unit (double spu)
498 TimeAxisView::set_samples_per_unit (spu);
505 _view->set_samples_per_unit (spu);
510 AutomationTimeAxisView::hide_clicked ()
512 // LAME fix for refreshing the hide button
513 hide_button.set_sensitive(false);
515 set_marked_for_display (false);
518 hide_button.set_sensitive(true);
522 AutomationTimeAxisView::build_display_menu ()
524 using namespace Menu_Helpers;
528 TimeAxisView::build_display_menu ();
530 /* now fill it with our stuff */
532 MenuList& items = display_menu->items();
534 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
535 items.push_back (SeparatorElem());
536 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
537 items.push_back (SeparatorElem());
541 Menu* auto_state_menu = manage (new Menu);
542 auto_state_menu->set_name ("ArdourContextMenu");
543 MenuList& as_items = auto_state_menu->items();
545 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
546 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
548 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
550 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
551 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
553 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
555 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
556 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
557 (AutoState) Write)));
558 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
560 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
561 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
562 (AutoState) Touch)));
563 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
565 items.push_back (MenuElem (_("State"), *auto_state_menu));
569 /* current interpolation state */
570 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
572 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
574 Menu* auto_mode_menu = manage (new Menu);
575 auto_mode_menu->set_name ("ArdourContextMenu");
576 MenuList& am_items = auto_mode_menu->items();
578 RadioMenuItem::Group group;
580 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
581 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
582 AutomationList::Discrete)));
583 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
584 mode_discrete_item->set_active (s == AutomationList::Discrete);
586 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
587 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
588 AutomationList::Linear)));
589 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
590 mode_line_item->set_active (s == AutomationList::Linear);
592 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
595 /* make sure the automation menu state is correct */
597 automation_state_changed ();
598 interpolation_changed (s);
602 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, framepos_t when, double y)
610 _canvas_display->w2i (x, y);
612 /* compute vertical fractional position */
614 y = 1.0 - (y / height);
618 _line->view_to_model_coord (x, y);
620 _session->begin_reversible_command (_("add automation event"));
621 XMLNode& before = _control->alist()->get_state();
623 _control->alist()->add (when, y);
625 XMLNode& after = _control->alist()->get_state();
626 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
628 _session->set_dirty ();
632 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
634 list<boost::shared_ptr<AutomationLine> > lines;
636 lines.push_back (_line);
638 lines = _view->get_lines ();
641 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
642 cut_copy_clear_one (**i, selection, op);
647 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
649 boost::shared_ptr<Evoral::ControlList> what_we_got;
650 boost::shared_ptr<AutomationList> alist (line.the_list());
652 XMLNode &before = alist->get_state();
654 /* convert time selection to automation list model coordinates */
655 const Evoral::TimeConverter<double, ARDOUR::framepos_t>& tc = line.time_converter ();
656 double const start = tc.from (selection.time.front().start - tc.origin_b ());
657 double const end = tc.from (selection.time.front().end - tc.origin_b ());
662 if ((what_we_got = alist->cut (start, end)) != 0) {
663 _editor.get_cut_buffer().add (what_we_got);
664 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
668 if ((what_we_got = alist->copy (start, end)) != 0) {
669 _editor.get_cut_buffer().add (what_we_got);
674 if ((what_we_got = alist->cut (start, end)) != 0) {
675 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
681 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
682 double when = (*x)->when;
683 double val = (*x)->value;
684 line.model_to_view_coord (when, val);
692 AutomationTimeAxisView::reset_objects (PointSelection& selection)
694 list<boost::shared_ptr<AutomationLine> > lines;
696 lines.push_back (_line);
698 lines = _view->get_lines ();
701 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
702 reset_objects_one (**i, selection);
707 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
709 boost::shared_ptr<AutomationList> alist(line.the_list());
711 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
713 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
715 if ((*i).track != this) {
719 alist->reset_range ((*i).start, (*i).end);
724 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
726 list<boost::shared_ptr<AutomationLine> > lines;
728 lines.push_back (_line);
730 lines = _view->get_lines ();
733 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
734 cut_copy_clear_objects_one (**i, selection, op);
739 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
741 boost::shared_ptr<Evoral::ControlList> what_we_got;
742 boost::shared_ptr<AutomationList> alist(line.the_list());
744 XMLNode &before = alist->get_state();
746 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
748 if ((*i).track != this) {
754 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
755 _editor.get_cut_buffer().add (what_we_got);
756 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
760 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
761 _editor.get_cut_buffer().add (what_we_got);
766 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
767 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
776 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
777 double when = (*x)->when;
778 double val = (*x)->value;
779 line.model_to_view_coord (when, val);
786 /** Paste a selection.
787 * @param pos Position to paste to (session frames).
788 * @param times Number of times to paste.
789 * @param selection Selection to paste.
790 * @param nth Index of the AutomationList within the selection to paste from.
793 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
795 boost::shared_ptr<AutomationLine> line;
800 line = _view->paste_line (pos);
807 return paste_one (*line, pos, times, selection, nth);
811 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
813 AutomationSelection::iterator p;
814 boost::shared_ptr<AutomationList> alist(line.the_list());
816 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
818 if (p == selection.lines.end()) {
822 /* Make a copy of the list because we have to scale the
823 values from view coordinates to model coordinates, and we're
824 not supposed to modify the points in the selection.
827 AutomationList copy (**p);
829 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
830 double when = (*x)->when;
831 double val = (*x)->value;
832 line.view_to_model_coord (when, val);
837 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
839 XMLNode &before = alist->get_state();
840 alist->paste (copy, model_pos, times);
841 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
847 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
849 if (!_line && !_view) {
853 if (touched (top, bot)) {
855 /* remember: this is X Window - coordinate space starts in upper left and moves down.
856 _y_position is the "origin" or "top" of the track.
859 /* bottom of our track */
860 double const mybot = _y_position + height;
865 if (_y_position >= top && mybot <= bot) {
867 /* _y_position is below top, mybot is above bot, so we're fully
876 /* top and bot are within _y_position .. mybot */
878 topfrac = 1.0 - ((top - _y_position) / height);
879 botfrac = 1.0 - ((bot - _y_position) / height);
884 _line->get_selectables (start, end, botfrac, topfrac, results);
886 _view->get_selectables (start, end, botfrac, topfrac, results);
892 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
895 _line->get_inverted_selectables (sel, result);
900 AutomationTimeAxisView::set_selected_points (PointSelection& points)
903 _line->set_selected_points (points);
905 _view->set_selected_points (points);
910 AutomationTimeAxisView::clear_lines ()
913 _list_connections.drop_connections ();
917 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
921 assert(line->the_list() == _control->list());
923 _control->alist()->automation_state_changed.connect (
924 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
927 _control->alist()->InterpolationChanged.connect (
928 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
932 //_controller = AutomationController::create(_session, line->the_list(), _control);
934 line->set_height (height);
936 /* pick up the current state */
937 automation_state_changed ();
943 AutomationTimeAxisView::entered()
946 _line->track_entered();
951 AutomationTimeAxisView::exited ()
954 _line->track_exited();
959 AutomationTimeAxisView::color_handler ()
967 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
969 TimeAxisView::set_state (node, version);
971 if (version < 3000) {
972 return set_state_2X (node, version);
975 XMLProperty const * type = node.property ("automation-id");
976 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
977 XMLProperty const * shown = node.property ("shown");
978 if (shown && shown->value () == "yes") {
979 set_marked_for_display (true);
980 _canvas_display->show (); /* FIXME: necessary? show_at? */
984 if (!_marked_for_display) {
993 AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/)
995 if (node.name() == X_("gain") && _control->parameter() == Evoral::Parameter (GainAutomation)) {
996 XMLProperty const * shown = node.property (X_("shown"));
997 if (shown && string_is_affirmative (shown->value ())) {
998 set_marked_for_display (true);
999 _canvas_display->show (); /* FIXME: necessary? show_at? */
1003 if (!_marked_for_display) {
1011 AutomationTimeAxisView::get_state_node ()
1013 TimeAxisView* state_parent = get_parent_with_state ();
1016 return state_parent->get_automation_child_xml_node (_control->parameter());
1023 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
1025 XMLNode* xml_node = get_state_node();
1027 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
1032 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
1034 update_extra_xml_shown (true);
1036 return TimeAxisView::show_at (y, nth, parent);
1040 AutomationTimeAxisView::hide ()
1042 update_extra_xml_shown (false);
1044 TimeAxisView::hide ();
1048 AutomationTimeAxisView::set_visibility (bool yn)
1050 bool changed = TimeAxisView::set_visibility (yn);
1053 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1059 /** @return true if this view has any automation data to display */
1061 AutomationTimeAxisView::has_automation () const
1063 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );
1066 list<boost::shared_ptr<AutomationLine> >
1067 AutomationTimeAxisView::lines () const
1069 list<boost::shared_ptr<AutomationLine> > lines;
1072 lines.push_back (_line);
1074 lines = _view->get_lines ();