X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fautomation_time_axis.cc;h=5391e78c6315224bde2be40260fd2dcb50c50c6c;hb=bca507a80811e0878f976434767bc45cd61f5ab3;hp=c00b6fcf448b8204bb0c4b96e4fee2c9ea53336c;hpb=64975776dc34a375b972896776f618752716785c;p=ardour.git diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index c00b6fcf44..5391e78c63 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "pbd/memento_command.h" #include "pbd/stacktrace.h" @@ -37,11 +39,10 @@ #include "route_time_axis.h" #include "automation_line.h" #include "public_editor.h" -#include "simplerect.h" #include "selection.h" #include "rgb_macros.h" #include "point_selection.h" -#include "canvas_impl.h" +#include "control_point.h" #include "utils.h" #include "i18n.h" @@ -85,6 +86,7 @@ AutomationTimeAxisView::AutomationTimeAxisView ( , _view (show_regions ? new AutomationStreamView (*this) : 0) , _name (nom) , auto_button (X_("")) /* force addition of a label */ + , _show_regions (show_regions) { if (!have_name_font) { name_font = get_font_for_style (X_("AutomationTrackName")); @@ -106,22 +108,17 @@ AutomationTimeAxisView::AutomationTimeAxisView ( ignore_state_request = false; first_call_to_set_height = true; - _base_rect = new SimpleRect(*_canvas_display); - _base_rect->property_x1() = 0.0; - _base_rect->property_y1() = 0.0; - /** gnomecanvas sometimes converts this value to int or adds 2 to it, so it must be - set correctly to avoid overflow. - */ - _base_rect->property_x2() = INT_MAX - 2; - _base_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get(); + _base_rect = new ArdourCanvas::Rectangle (_canvas_display); + _base_rect->set_x1 (ArdourCanvas::COORD_MAX); + _base_rect->set_outline_color (ARDOUR_UI::config()->canvasvar_AutomationTrackOutline.get()); /* outline ends and bottom */ - _base_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); - _base_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get(); + _base_rect->set_outline_what (0x1 | 0x2 | 0x8); + _base_rect->set_fill_color (ARDOUR_UI::config()->canvasvar_AutomationTrackFill.get()); _base_rect->set_data ("trackview", this); - _base_rect->signal_event().connect (sigc::bind ( + _base_rect->Event.connect (sigc::bind ( sigc::mem_fun (_editor, &PublicEditor::canvas_automation_track_event), _base_rect, this)); @@ -142,24 +139,19 @@ AutomationTimeAxisView::AutomationTimeAxisView ( ARDOUR_UI::instance()->set_tip(auto_button, _("automation state")); ARDOUR_UI::instance()->set_tip(hide_button, _("hide track")); - string str = gui_property ("height"); + const string str = gui_property ("height"); if (!str.empty()) { set_height (atoi (str)); } else { set_height (preset_height (HeightNormal)); } - /* rearrange the name display */ - - controls_table.remove (name_hbox); - controls_table.attach (name_hbox, 1, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 3, 0); - - /* we never show these for automation tracks, so make - life easier and remove them. - */ - - hide_name_entry(); + /* repack the name label */ + if (name_label.get_parent()) { + name_label.get_parent()->remove (name_label); + } + name_label.set_text (_name); name_label.set_alignment (Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); name_label.set_name (X_("TrackParameterName")); @@ -174,11 +166,17 @@ AutomationTimeAxisView::AutomationTimeAxisView ( /* add the buttons */ controls_table.attach (hide_button, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (auto_button, 6, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (name_label, 0, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (auto_button, 6, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + + name_label.show (); if (_controller) { + _controller.get()->set_size_request(-1, 24); /* add bar controller */ - controls_table.attach (*_controller.get(), 0, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (*_controller.get(), 1, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + /* note that this handler connects *before* the default handler */ + _controller->event_widget().signal_scroll_event().connect (mem_fun (*this, &AutomationTimeAxisView::controls_ebox_scroll), false); } controls_table.show_all (); @@ -193,8 +191,9 @@ AutomationTimeAxisView::AutomationTimeAxisView ( /* ask for notifications of any new RegionViews */ if (show_regions) { - assert(_view); - _view->attach (); + if (_view) { + _view->attach (); + } } else { /* no regions, just a single line for the entire track (e.g. bus gain) */ @@ -221,12 +220,13 @@ AutomationTimeAxisView::AutomationTimeAxisView ( ColorsChanged.connect (sigc::mem_fun (*this, &AutomationTimeAxisView::color_handler)); _route->DropReferences.connect ( - _route_connections, invalidator (*this), ui_bind (&AutomationTimeAxisView::route_going_away, this), gui_context () + _route_connections, invalidator (*this), boost::bind (&AutomationTimeAxisView::route_going_away, this), gui_context () ); } AutomationTimeAxisView::~AutomationTimeAxisView () { + delete _view; } void @@ -245,8 +245,8 @@ AutomationTimeAxisView::auto_clicked () automation_menu->set_name ("ArdourContextMenu"); MenuList& items (automation_menu->items()); - items.push_back (MenuElem (_("Manual"), sigc::bind (sigc::mem_fun(*this, - &AutomationTimeAxisView::set_automation_state), (AutoState) Off))); + items.push_back (MenuElem (S_("Automation|Manual"), sigc::bind (sigc::mem_fun(*this, + &AutomationTimeAxisView::set_automation_state), (AutoState) ARDOUR::Off))); items.push_back (MenuElem (_("Play"), sigc::bind (sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play))); items.push_back (MenuElem (_("Write"), sigc::bind (sigc::mem_fun(*this, @@ -292,12 +292,12 @@ AutomationTimeAxisView::automation_state_changed () assert (_control); state = _control->alist()->automation_state (); } else { - state = Off; + state = ARDOUR::Off; } - switch (state & (Off|Play|Touch|Write)) { - case Off: - auto_button.set_label (_("Manual")); + switch (state & (ARDOUR::Off|Play|Touch|Write)) { + case ARDOUR::Off: + auto_button.set_label (S_("Automation|Manual")); if (auto_off_item) { ignore_state_request = true; auto_off_item->set_active (true); @@ -403,7 +403,7 @@ AutomationTimeAxisView::set_height (uint32_t h) TimeAxisView::set_height (h); - _base_rect->property_y2() = h; + _base_rect->set_y1 (h); if (_line) { _line->set_height(h); @@ -419,28 +419,17 @@ AutomationTimeAxisView::set_height (uint32_t h) first_call_to_set_height = false; if (h >= preset_height (HeightNormal)) { - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - auto_button.show(); hide_button.show_all(); } else if (h >= preset_height (HeightSmall)) { controls_table.hide_all (); - hide_name_entry (); - show_name_label (); - name_hbox.show_all (); - auto_button.hide(); - hide_button.hide(); } - } else if (h >= preset_height (HeightNormal)) { - cerr << "track grown, but neither changed_between_small_and_normal nor first_call_to_set_height set!" << endl; } if (changed) { - if (canvas_item_visible (_canvas_display) && _route) { + if (_canvas_display->visible() && _route) { /* only emit the signal if the height really changed and we were visible */ _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */ } @@ -448,16 +437,16 @@ AutomationTimeAxisView::set_height (uint32_t h) } void -AutomationTimeAxisView::set_samples_per_unit (double spu) +AutomationTimeAxisView::set_frames_per_pixel (double fpp) { - TimeAxisView::set_samples_per_unit (spu); + TimeAxisView::set_frames_per_pixel (fpp); if (_line) { _line->reset (); } if (_view) { - _view->set_samples_per_unit (spu); + _view->set_frames_per_pixel (fpp); } } @@ -497,9 +486,9 @@ AutomationTimeAxisView::build_display_menu () auto_state_menu->set_name ("ArdourContextMenu"); MenuList& as_items = auto_state_menu->items(); - as_items.push_back (CheckMenuElem (_("Manual"), sigc::bind ( + as_items.push_back (CheckMenuElem (S_("Automation|Manual"), sigc::bind ( sigc::mem_fun(*this, &AutomationTimeAxisView::set_automation_state), - (AutoState) Off))); + (AutoState) ARDOUR::Off))); auto_off_item = dynamic_cast(&as_items.back()); as_items.push_back (CheckMenuElem (_("Play"), sigc::bind ( @@ -554,15 +543,24 @@ AutomationTimeAxisView::build_display_menu () } void -AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/, framepos_t when, double y) +AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when, double y) { if (!_line) { return; } + boost::shared_ptr list = _line->the_list (); + + if (list->in_write_pass()) { + /* do not allow the GUI to add automation events during an + automation write pass. + */ + return; + } + double x = 0; - _canvas_display->w2i (x, y); + _canvas_display->canvas_to_item (x, y); /* compute vertical fractional position */ @@ -572,7 +570,8 @@ AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkE _line->view_to_model_coord (x, y); - boost::shared_ptr list = _line->the_list (); + + _editor.snap_to_with_modifier (when, event); _session->begin_reversible_command (_("add automation event")); XMLNode& before = list->get_state(); @@ -584,172 +583,6 @@ AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* /*item*/, GdkE _session->set_dirty (); } -void -AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) -{ - list > lines; - if (_line) { - lines.push_back (_line); - } else if (_view) { - lines = _view->get_lines (); - } - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - cut_copy_clear_one (**i, selection, op); - } -} - -void -AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op) -{ - boost::shared_ptr what_we_got; - boost::shared_ptr alist (line.the_list()); - - XMLNode &before = alist->get_state(); - - /* convert time selection to automation list model coordinates */ - const Evoral::TimeConverter& tc = line.time_converter (); - double const start = tc.from (selection.time.front().start - tc.origin_b ()); - double const end = tc.from (selection.time.front().end - tc.origin_b ()); - - switch (op) { - case Delete: - if (alist->cut (start, end) != 0) { - _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); - } - break; - - case Cut: - - if ((what_we_got = alist->cut (start, end)) != 0) { - _editor.get_cut_buffer().add (what_we_got); - _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); - } - break; - case Copy: - if ((what_we_got = alist->copy (start, end)) != 0) { - _editor.get_cut_buffer().add (what_we_got); - } - break; - - case Clear: - if ((what_we_got = alist->cut (start, end)) != 0) { - _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); - } - break; - } - - if (what_we_got) { - for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) { - double when = (*x)->when; - double val = (*x)->value; - line.model_to_view_coord (when, val); - (*x)->when = when; - (*x)->value = val; - } - } -} - -void -AutomationTimeAxisView::reset_objects (PointSelection& selection) -{ - list > lines; - if (_line) { - lines.push_back (_line); - } else if (_view) { - lines = _view->get_lines (); - } - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - reset_objects_one (**i, selection); - } -} - -void -AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection) -{ - boost::shared_ptr alist(line.the_list()); - - _session->add_command (new MementoCommand(*alist.get(), &alist->get_state(), 0)); - - for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { - - if ((*i).track != this) { - continue; - } - - alist->reset_range ((*i).start, (*i).end); - } -} - -void -AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op) -{ - list > lines; - if (_line) { - lines.push_back (_line); - } else if (_view) { - lines = _view->get_lines (); - } - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - cut_copy_clear_objects_one (**i, selection, op); - } -} - -void -AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op) -{ - boost::shared_ptr what_we_got; - boost::shared_ptr alist(line.the_list()); - - XMLNode &before = alist->get_state(); - - for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) { - - if ((*i).track != this) { - continue; - } - - switch (op) { - case Delete: - if (alist->cut ((*i).start, (*i).end) != 0) { - _session->add_command (new MementoCommand(*alist.get(), new XMLNode (before), &alist->get_state())); - } - break; - case Cut: - if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) { - _editor.get_cut_buffer().add (what_we_got); - _session->add_command (new MementoCommand(*alist.get(), new XMLNode (before), &alist->get_state())); - } - break; - case Copy: - if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) { - _editor.get_cut_buffer().add (what_we_got); - } - break; - - case Clear: - if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) { - _session->add_command (new MementoCommand(*alist.get(), new XMLNode (before), &alist->get_state())); - } - break; - } - } - - delete &before; - - if (what_we_got) { - for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) { - double when = (*x)->when; - double val = (*x)->value; - line.model_to_view_coord (when, val); - (*x)->when = when; - (*x)->value = val; - } - } -} - /** Paste a selection. * @param pos Position to paste to (session frames). * @param times Number of times to paste. @@ -780,31 +613,21 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float t AutomationSelection::iterator p; boost::shared_ptr alist(line.the_list()); - for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {} - - if (p == selection.lines.end()) { + if (_session->transport_rolling() && alist->automation_write()) { + /* do not paste if this control is in write mode and we're rolling */ return false; } - /* Make a copy of the list because we have to scale the - values from view coordinates to model coordinates, and we're - not supposed to modify the points in the selection. - */ - - AutomationList copy (**p); + for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth) {} - for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) { - double when = (*x)->when; - double val = (*x)->value; - line.view_to_model_coord (when, val); - (*x)->when = when; - (*x)->value = val; + if (p == selection.lines.end()) { + return false; } double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ()); XMLNode &before = alist->get_state(); - alist->paste (copy, model_pos, times); + alist->paste (**p, model_pos, times); _session->add_command (new MementoCommand(*alist.get(), &before, &alist->get_state())); return true; @@ -883,9 +706,7 @@ AutomationTimeAxisView::clear_lines () void AutomationTimeAxisView::add_line (boost::shared_ptr line) { - assert(line); - assert(!_line); - if (_control) { + if (_control && line) { assert(line->the_list() == _control->list()); _control->alist()->automation_state_changed.connect ( @@ -904,7 +725,7 @@ AutomationTimeAxisView::add_line (boost::shared_ptr line) /* pick up the current state */ automation_state_changed (); - line->show(); + line->add_visibility (AutomationLine::Line); } void @@ -941,9 +762,9 @@ AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/) if (yn) { _canvas_display->show (); /* FIXME: necessary? show_at? */ } - set_gui_property ("visible", (yn ? "yes" : "no")); + set_gui_property ("visible", yn); } else { - set_gui_property ("visible", "no"); + set_gui_property ("visible", false); } } @@ -951,7 +772,7 @@ AutomationTimeAxisView::set_state_2X (const XMLNode& node, int /*version*/) } int -AutomationTimeAxisView::set_state (const XMLNode& node, int /*version*/) +AutomationTimeAxisView::set_state (const XMLNode&, int /*version*/) { return 0; } @@ -1020,6 +841,121 @@ AutomationTimeAxisView::state_id() const _route->id(), _parameter.type(), _parameter.id(), - _parameter.channel()); + (int) _parameter.channel()); + } +} + +/** Given a state id string, see if it is one generated by + * this class. If so, parse it into its components. + * @param state_id State ID string to parse. + * @param route_id Filled in with the route's ID if the state ID string is parsed. + * @param has_parameter Filled in with true if the state ID has a parameter, otherwise false. + * @param parameter Filled in with the state ID's parameter, if it has one. + * @return true if this is a state ID generated by this class, otherwise false. + */ + +bool +AutomationTimeAxisView::parse_state_id ( + string const & state_id, + PBD::ID & route_id, + bool & has_parameter, + Evoral::Parameter & parameter) +{ + stringstream s; + s << state_id; + + string a, b, c; + s >> a >> b >> c; + + if (a != X_("automation")) { + return false; + } + + route_id = PBD::ID (b); + + if (c.empty ()) { + has_parameter = false; + return true; + } + + has_parameter = true; + + vector p; + boost::split (p, c, boost::is_any_of ("/")); + + assert (p.size() == 3); + + parameter = Evoral::Parameter ( + boost::lexical_cast (p[0]), + boost::lexical_cast (p[2]), + boost::lexical_cast (p[1]) + ); + + return true; +} + +void +AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) +{ + list > lines; + if (_line) { + lines.push_back (_line); + } else if (_view) { + lines = _view->get_lines (); + } + + for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { + cut_copy_clear_one (**i, selection, op); + } +} + +void +AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op) +{ + boost::shared_ptr what_we_got; + boost::shared_ptr alist (line.the_list()); + + XMLNode &before = alist->get_state(); + + /* convert time selection to automation list model coordinates */ + const Evoral::TimeConverter& tc = line.time_converter (); + double const start = tc.from (selection.time.front().start - tc.origin_b ()); + double const end = tc.from (selection.time.front().end - tc.origin_b ()); + + switch (op) { + case Delete: + if (alist->cut (start, end) != 0) { + _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); + } + break; + + case Cut: + + if ((what_we_got = alist->cut (start, end)) != 0) { + _editor.get_cut_buffer().add (what_we_got); + _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); + } + break; + case Copy: + if ((what_we_got = alist->copy (start, end)) != 0) { + _editor.get_cut_buffer().add (what_we_got); + } + break; + + case Clear: + if ((what_we_got = alist->cut (start, end)) != 0) { + _session->add_command(new MementoCommand(*alist.get(), &before, &alist->get_state())); + } + break; + } + + if (what_we_got) { + for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) { + double when = (*x)->when; + double val = (*x)->value; + line.model_to_view_coord (when, val); + (*x)->when = when; + (*x)->value = val; + } } }