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 (Session* s, boost::shared_ptr<Route> r,
63 boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
64 PublicEditor& e, TimeAxisView& parent, bool show_regions,
65 ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
67 TimeAxisView (s, e, &parent, canvas),
71 _controller(AutomationController::create(a, c->parameter(), c)),
73 _view (show_regions ? new AutomationStreamView(*this) : NULL),
75 auto_button (X_("")) /* force addition of a label */
77 if (!have_name_font) {
78 name_font = get_font_for_style (X_("AutomationTrackName"));
79 have_name_font = true;
87 mode_discrete_item = 0;
90 ignore_state_request = false;
91 first_call_to_set_height = true;
93 _base_rect = new SimpleRect(*_canvas_display);
94 _base_rect->property_x1() = 0.0;
95 _base_rect->property_y1() = 0.0;
96 /** gnomecanvas sometimes converts this value to int or adds 2 to it, so it must be
97 set correctly to avoid overflow.
99 _base_rect->property_x2() = INT_MAX - 2;
100 _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get();
102 /* outline ends and bottom */
103 _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
104 _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get();
106 _base_rect->set_data ("trackview", this);
108 _base_rect->signal_event().connect (sigc::bind (
109 sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event),
113 _base_rect->lower_to_bottom();
116 hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
118 auto_button.set_name ("TrackVisualButton");
119 hide_button.set_name ("TrackRemoveButton");
121 auto_button.unset_flags (Gtk::CAN_FOCUS);
122 hide_button.unset_flags (Gtk::CAN_FOCUS);
124 controls_table.set_no_show_all();
126 ARDOUR_UI::instance()->set_tip(auto_button, _("automation state"));
127 ARDOUR_UI::instance()->set_tip(hide_button, _("hide track"));
129 /* rearrange the name display */
131 /* we never show these for automation tracks, so make
132 life easier and remove them.
137 /* move the name label over a bit */
139 string shortpname = _name;
140 bool shortened = false;
143 shortpname = fit_to_pixels (_name, 60, *name_font, ignore_width, true);
145 if (shortpname != _name ){
149 name_label.set_text (shortpname);
150 name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
151 name_label.set_name (X_("TrackParameterName"));
153 if (nomparent.length()) {
155 /* limit the plug name string */
157 string pname = fit_to_pixels (nomparent, 60, *name_font, ignore_width, true);
158 if (pname != nomparent) {
162 plugname = new Label (pname);
163 plugname->set_name (X_("TrackPlugName"));
165 controls_table.remove (name_hbox);
166 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
167 plugname_packed = true;
168 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
171 plugname_packed = false;
175 string tipname = nomparent;
176 if (!tipname.empty()) {
180 ARDOUR_UI::instance()->set_tip(controls_ebox, tipname);
183 /* add the buttons */
184 controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
186 controls_table.attach (auto_button, 5, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
188 /* add bar controller */
189 controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
191 controls_table.show_all ();
193 hide_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked));
194 auto_button.signal_clicked().connect (sigc::mem_fun(*this, &AutomationTimeAxisView::auto_clicked));
196 controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
197 controls_base_unselected_name = X_("AutomationTrackControlsBase");
198 controls_ebox.set_name (controls_base_unselected_name);
200 XMLNode* xml_node = get_parent_with_state()->get_automation_child_xml_node (_control->parameter());
203 set_state (*xml_node, Stateful::loading_state_version);
206 /* ask for notifications of any new RegionViews */
212 /* no regions, just a single line for the entire track (e.g. bus gain) */
214 boost::shared_ptr<AutomationLine> line(new AutomationLine (
215 ARDOUR::EventTypeMap::instance().to_symbol(_control->parameter()),
220 line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
221 line->queue_reset ();
225 /* make sure labels etc. are correct */
227 automation_state_changed ();
228 ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler));
231 AutomationTimeAxisView::~AutomationTimeAxisView ()
236 AutomationTimeAxisView::auto_clicked ()
238 using namespace Menu_Helpers;
240 if (automation_menu == 0) {
241 automation_menu = manage (new Menu);
242 automation_menu->set_name ("ArdourContextMenu");
243 MenuList& items (automation_menu->items());
245 items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this,
246 &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
247 items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this,
248 &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
249 items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this,
250 &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
251 items.push_back (MenuElem (_("Touch"), sigc::bind (sigc::mem_fun(*this,
252 &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
255 automation_menu->popup (1, gtk_get_current_event_time());
259 AutomationTimeAxisView::set_automation_state (AutoState state)
261 if (ignore_state_request) {
266 _automatable->set_parameter_automation_state (_control->parameter(), state);
269 if (_route == _automatable) { // This is a time axis for route (not region) automation
270 _route->set_parameter_automation_state (_control->parameter(), state);
273 if (_control->list()) {
274 _control->alist()->set_automation_state(state);
278 _view->set_automation_state (state);
280 /* AutomationStreamViews don't signal when their automation state changes, so handle
281 our updates `manually'.
283 automation_state_changed ();
288 AutomationTimeAxisView::automation_state_changed ()
292 /* update button label */
295 state = _control->alist()->automation_state ();
297 state = _view->automation_state ();
302 switch (state & (Off|Play|Touch|Write)) {
304 auto_button.set_label (_("Manual"));
306 ignore_state_request = true;
307 auto_off_item->set_active (true);
308 auto_play_item->set_active (false);
309 auto_touch_item->set_active (false);
310 auto_write_item->set_active (false);
311 ignore_state_request = false;
315 auto_button.set_label (_("Play"));
316 if (auto_play_item) {
317 ignore_state_request = true;
318 auto_play_item->set_active (true);
319 auto_off_item->set_active (false);
320 auto_touch_item->set_active (false);
321 auto_write_item->set_active (false);
322 ignore_state_request = false;
326 auto_button.set_label (_("Write"));
327 if (auto_write_item) {
328 ignore_state_request = true;
329 auto_write_item->set_active (true);
330 auto_off_item->set_active (false);
331 auto_play_item->set_active (false);
332 auto_touch_item->set_active (false);
333 ignore_state_request = false;
337 auto_button.set_label (_("Touch"));
338 if (auto_touch_item) {
339 ignore_state_request = true;
340 auto_touch_item->set_active (true);
341 auto_off_item->set_active (false);
342 auto_play_item->set_active (false);
343 auto_write_item->set_active (false);
344 ignore_state_request = false;
348 auto_button.set_label (_("???"));
353 /** The interpolation style of our AutomationList has changed, so update */
355 AutomationTimeAxisView::interpolation_changed (AutomationList::InterpolationStyle s)
357 if (mode_line_item && mode_discrete_item) {
358 if (s == AutomationList::Discrete) {
359 mode_discrete_item->set_active(true);
360 mode_line_item->set_active(false);
362 mode_line_item->set_active(true);
363 mode_discrete_item->set_active(false);
368 /** A menu item has been selected to change our interpolation mode */
370 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
372 /* Tell our view's list, if we have one, otherwise tell our own.
373 * Everything else will be signalled back from that.
377 _view->set_interpolation (style);
379 _control->list()->set_interpolation (style);
384 AutomationTimeAxisView::clear_clicked ()
386 assert (_line || _view);
388 _session->begin_reversible_command (_("clear automation"));
396 _session->commit_reversible_command ();
397 _session->set_dirty ();
401 AutomationTimeAxisView::set_height (uint32_t h)
403 bool const changed = (height != (uint32_t) h) || first_call_to_set_height;
404 uint32_t const normal = preset_height (HeightNormal);
405 bool const changed_between_small_and_normal = ( (height < normal && h >= normal) || (height >= normal || h < normal) );
407 TimeAxisView* state_parent = get_parent_with_state ();
408 assert(state_parent);
409 XMLNode* xml_node = state_parent->get_automation_child_xml_node (_control->parameter());
411 TimeAxisView::set_height (h);
412 _base_rect->property_y2() = h;
415 _line->set_height(h);
419 _view->set_height(h);
420 _view->update_contents_height();
424 snprintf (buf, sizeof (buf), "%u", height);
426 xml_node->add_property ("height", buf);
429 if (changed_between_small_and_normal || first_call_to_set_height) {
431 first_call_to_set_height = false;
433 if (h >= preset_height (HeightNormal)) {
434 controls_table.remove (name_hbox);
437 if (plugname_packed) {
438 controls_table.remove (*plugname);
439 plugname_packed = false;
441 controls_table.attach (*plugname, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
442 plugname_packed = true;
443 controls_table.attach (name_hbox, 1, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
445 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
449 name_hbox.show_all ();
452 hide_button.show_all();
454 } else if (h >= preset_height (HeightSmall)) {
455 controls_table.remove (name_hbox);
457 if (plugname_packed) {
458 controls_table.remove (*plugname);
459 plugname_packed = false;
462 controls_table.attach (name_hbox, 1, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
463 controls_table.hide_all ();
466 name_hbox.show_all ();
471 } else if (h >= preset_height (HeightNormal)) {
472 cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl;
476 if (canvas_item_visible (_canvas_display)) {
477 /* only emit the signal if the height really changed and we were visible */
478 _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
484 AutomationTimeAxisView::set_samples_per_unit (double spu)
486 TimeAxisView::set_samples_per_unit (spu);
493 _view->set_samples_per_unit (spu);
498 AutomationTimeAxisView::hide_clicked ()
500 // LAME fix for refreshing the hide button
501 hide_button.set_sensitive(false);
503 set_marked_for_display (false);
506 hide_button.set_sensitive(true);
510 AutomationTimeAxisView::build_display_menu ()
512 using namespace Menu_Helpers;
516 TimeAxisView::build_display_menu ();
518 /* now fill it with our stuff */
520 MenuList& items = display_menu->items();
522 items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &AutomationTimeAxisView::hide_clicked)));
523 items.push_back (SeparatorElem());
524 items.push_back (MenuElem (_("Clear"), sigc::mem_fun(*this, &AutomationTimeAxisView::clear_clicked)));
525 items.push_back (SeparatorElem());
529 Menu* auto_state_menu = manage (new Menu);
530 auto_state_menu->set_name ("ArdourContextMenu");
531 MenuList& as_items = auto_state_menu->items();
533 as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind (
534 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
536 auto_off_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
538 as_items.push_back (CheckMenuElem (_("Play"), sigc::bind (
539 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
541 auto_play_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
543 as_items.push_back (CheckMenuElem (_("Write"), sigc::bind (
544 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
545 (AutoState) Write)));
546 auto_write_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
548 as_items.push_back (CheckMenuElem (_("Touch"), sigc::bind (
549 sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state),
550 (AutoState) Touch)));
551 auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back());
553 items.push_back (MenuElem (_("State"), *auto_state_menu));
557 /* current interpolation state */
558 AutomationList::InterpolationStyle const s = _view ? _view->interpolation() : _control->list()->interpolation ();
560 if (EventTypeMap::instance().is_midi_parameter(_control->parameter())) {
562 Menu* auto_mode_menu = manage (new Menu);
563 auto_mode_menu->set_name ("ArdourContextMenu");
564 MenuList& am_items = auto_mode_menu->items();
566 RadioMenuItem::Group group;
568 am_items.push_back (RadioMenuElem (group, _("Discrete"), sigc::bind (
569 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
570 AutomationList::Discrete)));
571 mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
572 mode_discrete_item->set_active (s == AutomationList::Discrete);
574 am_items.push_back (RadioMenuElem (group, _("Linear"), sigc::bind (
575 sigc::mem_fun(*this, &AutomationTimeAxisView::set_interpolation),
576 AutomationList::Linear)));
577 mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back());
578 mode_line_item->set_active (s == AutomationList::Linear);
580 items.push_back (MenuElem (_("Mode"), *auto_mode_menu));
583 /* make sure the automation menu state is correct */
585 automation_state_changed ();
586 interpolation_changed (s);
590 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, framepos_t when, double y)
597 _canvas_display->w2i (x, y);
599 /* compute vertical fractional position */
601 y = 1.0 - (y / height);
605 _line->view_to_model_coord (x, y);
607 _session->begin_reversible_command (_("add automation event"));
608 XMLNode& before = _control->alist()->get_state();
610 _control->alist()->add (when, y);
612 XMLNode& after = _control->alist()->get_state();
613 _session->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(*_control->alist(), &before, &after));
615 _session->set_dirty ();
619 AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
621 list<boost::shared_ptr<AutomationLine> > lines;
623 lines.push_back (_line);
625 lines = _view->get_lines ();
628 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
629 cut_copy_clear_one (**i, selection, op);
634 AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
636 boost::shared_ptr<Evoral::ControlList> what_we_got;
637 boost::shared_ptr<AutomationList> alist (line.the_list());
639 XMLNode &before = alist->get_state();
641 /* convert time selection to automation list model coordinates */
642 const Evoral::TimeConverter<double, ARDOUR::framepos_t>& tc = line.time_converter ();
643 double const start = tc.from (selection.time.front().start - tc.origin_b ());
644 double const end = tc.from (selection.time.front().end - tc.origin_b ());
649 if ((what_we_got = alist->cut (start, end)) != 0) {
650 _editor.get_cut_buffer().add (what_we_got);
651 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
655 if ((what_we_got = alist->copy (start, end)) != 0) {
656 _editor.get_cut_buffer().add (what_we_got);
661 if ((what_we_got = alist->cut (start, end)) != 0) {
662 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
668 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
669 double when = (*x)->when;
670 double val = (*x)->value;
671 line.model_to_view_coord (when, val);
679 AutomationTimeAxisView::reset_objects (PointSelection& selection)
681 list<boost::shared_ptr<AutomationLine> > lines;
683 lines.push_back (_line);
685 lines = _view->get_lines ();
688 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
689 reset_objects_one (**i, selection);
694 AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
696 boost::shared_ptr<AutomationList> alist(line.the_list());
698 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
700 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
702 if ((*i).track != this) {
706 alist->reset_range ((*i).start, (*i).end);
711 AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
713 list<boost::shared_ptr<AutomationLine> > lines;
715 lines.push_back (_line);
717 lines = _view->get_lines ();
720 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
721 cut_copy_clear_objects_one (**i, selection, op);
726 AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
728 boost::shared_ptr<Evoral::ControlList> what_we_got;
729 boost::shared_ptr<AutomationList> alist(line.the_list());
731 XMLNode &before = alist->get_state();
733 for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
735 if ((*i).track != this) {
741 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
742 _editor.get_cut_buffer().add (what_we_got);
743 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
747 if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
748 _editor.get_cut_buffer().add (what_we_got);
753 if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
754 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
763 for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
764 double when = (*x)->when;
765 double val = (*x)->value;
766 line.model_to_view_coord (when, val);
773 /** Paste a selection.
774 * @param pos Position to paste to (session frames).
775 * @param times Number of times to paste.
776 * @param selection Selection to paste.
777 * @param nth Index of the AutomationList within the selection to paste from.
780 AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
782 boost::shared_ptr<AutomationLine> line;
787 line = _view->paste_line (pos);
794 return paste_one (*line, pos, times, selection, nth);
798 AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth)
800 AutomationSelection::iterator p;
801 boost::shared_ptr<AutomationList> alist(line.the_list());
803 for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {}
805 if (p == selection.lines.end()) {
809 /* Make a copy of the list because we have to scale the
810 values from view coordinates to model coordinates, and we're
811 not supposed to modify the points in the selection.
814 AutomationList copy (**p);
816 for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
817 double when = (*x)->when;
818 double val = (*x)->value;
819 line.view_to_model_coord (when, val);
824 double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
826 XMLNode &before = alist->get_state();
827 alist->paste (copy, model_pos, times);
828 _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
834 AutomationTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
836 if (!_line && !_view) {
840 if (touched (top, bot)) {
842 /* remember: this is X Window - coordinate space starts in upper left and moves down.
843 _y_position is the "origin" or "top" of the track.
846 /* bottom of our track */
847 double const mybot = _y_position + height;
852 if (_y_position >= top && mybot <= bot) {
854 /* _y_position is below top, mybot is above bot, so we're fully
863 /* top and bot are within _y_position .. mybot */
865 topfrac = 1.0 - ((top - _y_position) / height);
866 botfrac = 1.0 - ((bot - _y_position) / height);
871 _line->get_selectables (start, end, botfrac, topfrac, results);
873 _view->get_selectables (start, end, botfrac, topfrac, results);
879 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
882 _line->get_inverted_selectables (sel, result);
887 AutomationTimeAxisView::set_selected_points (PointSelection& points)
890 _line->set_selected_points (points);
892 _view->set_selected_points (points);
897 AutomationTimeAxisView::clear_lines ()
900 _list_connections.drop_connections ();
904 AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
908 assert(line->the_list() == _control->list());
910 _control->alist()->automation_state_changed.connect (
911 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::automation_state_changed, this), gui_context()
914 _control->alist()->InterpolationChanged.connect (
915 _list_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::interpolation_changed, this, _1), gui_context()
919 //_controller = AutomationController::create(_session, line->the_list(), _control);
921 line->set_height (height);
923 /* pick up the current state */
924 automation_state_changed ();
930 AutomationTimeAxisView::entered()
933 _line->track_entered();
937 AutomationTimeAxisView::exited ()
940 _line->track_exited();
944 AutomationTimeAxisView::color_handler ()
952 AutomationTimeAxisView::set_state (const XMLNode& node, int version)
954 TimeAxisView::set_state (node, version);
956 if (version < 3000) {
957 return set_state_2X (node, version);
960 XMLProperty const * type = node.property ("automation-id");
961 if (type && type->value () == ARDOUR::EventTypeMap::instance().to_symbol (_control->parameter())) {
962 XMLProperty const * shown = node.property ("shown");
963 if (shown && shown->value () == "yes") {
964 set_marked_for_display (true);
965 _canvas_display->show (); /* FIXME: necessary? show_at? */
969 if (!_marked_for_display) {
978 AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/)
980 if (node.name() == X_("gain") && _control->parameter() == Evoral::Parameter (GainAutomation)) {
981 XMLProperty const * shown = node.property (X_("shown"));
982 if (shown && string_is_affirmative (shown->value ())) {
983 set_marked_for_display (true);
984 _canvas_display->show (); /* FIXME: necessary? show_at? */
988 if (!_marked_for_display) {
996 AutomationTimeAxisView::get_state_node ()
998 TimeAxisView* state_parent = get_parent_with_state ();
1001 return state_parent->get_automation_child_xml_node (_control->parameter());
1008 AutomationTimeAxisView::update_extra_xml_shown (bool editor_shown)
1010 XMLNode* xml_node = get_state_node();
1012 xml_node->add_property ("shown", editor_shown ? "yes" : "no");
1017 AutomationTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
1019 update_extra_xml_shown (true);
1021 return TimeAxisView::show_at (y, nth, parent);
1025 AutomationTimeAxisView::hide ()
1027 update_extra_xml_shown (false);
1029 TimeAxisView::hide ();
1033 AutomationTimeAxisView::set_visibility (bool yn)
1035 bool changed = TimeAxisView::set_visibility (yn);
1038 get_state_node()->add_property ("shown", yn ? X_("yes") : X_("no"));
1044 /** @return true if this view has any automation data to display */
1046 AutomationTimeAxisView::has_automation () const
1048 return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) );
1051 list<boost::shared_ptr<AutomationLine> >
1052 AutomationTimeAxisView::lines () const
1054 list<boost::shared_ptr<AutomationLine> > lines;
1057 lines.push_back (_line);
1059 lines = _view->get_lines ();