From 939cff515018f9a5123e90a182dec56efdd7c508 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 15 Jul 2009 20:29:02 +0000 Subject: [PATCH] more hacking on the processor list and processor box - note that ctrl-x/c/v now work "as expected" and / is a keystroke for toggling active state. cut-n-paste ops should all basically work git-svn-id: svn://localhost/ardour2/branches/3.0@5366 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour.menus.in | 2 + gtk2_ardour/processor_box.cc | 233 +++++++++++++++++-------- gtk2_ardour/processor_box.h | 18 +- libs/ardour/ardour/io_processor.h | 1 + libs/ardour/ardour/route.h | 3 +- libs/ardour/io_processor.cc | 12 ++ libs/ardour/route.cc | 175 +++++++++++++++---- libs/gtkmm2ext/gtkmm2ext/dndtreeview.h | 8 +- 8 files changed, 333 insertions(+), 119 deletions(-) diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index 4254cb3fc2..1029645861 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -455,6 +455,8 @@ + + diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index e874550712..7b7d18f7e7 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -197,15 +197,26 @@ ProcessorBox::route_going_away () void -ProcessorBox::object_drop (const list >& procs, Gtk::TreeView* source, Glib::RefPtr& context) +ProcessorBox::object_drop (const list >& procs, Gtk::TreeView* source, int x, int y, Glib::RefPtr& context) { - cerr << "Drop from " << source << " (mine is " << &processor_display << ") action = " << hex << context->get_suggested_action() << dec << endl; - + TreeIter iter; + TreeModel::Path path; + TreeViewColumn* column; + int cellx; + int celly; + boost::shared_ptr p; + + if (processor_display.get_path_at_pos (x, y, path, column, cellx, celly)) { + if ((iter = model->get_iter (path))) { + p = (*iter)[columns.processor]; + } + } + for (list >::const_iterator i = procs.begin(); i != procs.end(); ++i) { XMLNode& state = (*i)->get_state (); XMLNodeList nlist; nlist.push_back (&state); - paste_processor_state (nlist); + paste_processor_state (nlist, p); delete &state; } @@ -373,14 +384,33 @@ ProcessorBox::processor_key_release_event (GdkEventKey *ev) } } - if (targets.empty()) { - return ret; - } - + switch (ev->keyval) { + case GDK_c: + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + copy_processors (targets); + } + break; + + case GDK_x: + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + cut_processors (targets); + } + break; + + case GDK_v: + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + if (targets.empty()) { + paste_processors (); + } else { + paste_processors (targets.front()); + } + } + break; + case GDK_Delete: case GDK_BackSpace: - delete_processors (); + delete_processors (targets); ret = true; break; @@ -432,7 +462,7 @@ ProcessorBox::processor_button_press_event (GdkEventButton *ev) } else if (processor && ev->button == 1 && selected) { - // this is purely informational but necessary + // this is purely informational but necessary for route params UI ProcessorSelected (processor); // emit } else if (!processor && ev->button == 1 && ev->type == GDK_2BUTTON_PRESS) { @@ -964,19 +994,26 @@ void ProcessorBox::cut_processors () { ProcSelection to_be_removed; - XMLNode* node = new XMLNode (X_("cut")); get_selected_processors (to_be_removed); +} +void +ProcessorBox::cut_processors (const ProcSelection& to_be_removed) +{ if (to_be_removed.empty()) { return; } + XMLNode* node = new XMLNode (X_("cut")); + Route::ProcessorList to_cut; + no_processor_redisplay = true; - for (ProcSelection::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) { - // Do not cut inserts + for (ProcSelection::const_iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) { + // Cut only plugins, sends and returns if (boost::dynamic_pointer_cast((*i)) != 0 || - (boost::dynamic_pointer_cast((*i)) != 0)) { + (boost::dynamic_pointer_cast((*i)) != 0) || + (boost::dynamic_pointer_cast((*i)) != 0)) { void* gui = (*i)->get_gui (); @@ -985,15 +1022,16 @@ ProcessorBox::cut_processors () } XMLNode& child ((*i)->get_state()); - - if (_route->remove_processor (*i) == 0) { - /* success */ - node->add_child_nocopy (child); - } else { - delete &child; - } + node->add_child_nocopy (child); + to_cut.push_back (*i); } } + + if (_route->remove_processors (to_cut) != 0) { + delete node; + no_processor_redisplay = false; + return; + } _rr_selection.set (node); @@ -1005,18 +1043,24 @@ void ProcessorBox::copy_processors () { ProcSelection to_be_copied; - XMLNode* node = new XMLNode (X_("copy")); - get_selected_processors (to_be_copied); + copy_processors (to_be_copied); +} +void +ProcessorBox::copy_processors (const ProcSelection& to_be_copied) +{ if (to_be_copied.empty()) { return; } - for (ProcSelection::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) { - // Do not copy inserts + XMLNode* node = new XMLNode (X_("copy")); + + for (ProcSelection::const_iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) { + // Copy only plugins, sends, returns if (boost::dynamic_pointer_cast((*i)) != 0 || - (boost::dynamic_pointer_cast((*i)) != 0)) { + (boost::dynamic_pointer_cast((*i)) != 0) || + (boost::dynamic_pointer_cast((*i)) != 0)) { node->add_child_nocopy ((*i)->get_state()); } } @@ -1028,16 +1072,20 @@ void ProcessorBox::delete_processors () { ProcSelection to_be_deleted; - get_selected_processors (to_be_deleted); + delete_processors (to_be_deleted); +} - if (to_be_deleted.empty()) { +void +ProcessorBox::delete_processors (const ProcSelection& targets) +{ + if (targets.empty()) { return; } no_processor_redisplay = true; - for (ProcSelection::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) { + for (ProcSelection::const_iterator i = targets.begin(); i != targets.end(); ++i) { void* gui = (*i)->get_gui (); @@ -1123,59 +1171,66 @@ ProcessorBox::paste_processors () return; } - cerr << "paste from node called " << _rr_selection.processors.get_node().name() << endl; - - paste_processor_state (_rr_selection.processors.get_node().children()); + paste_processor_state (_rr_selection.processors.get_node().children(), boost::shared_ptr()); } void -ProcessorBox::paste_processor_state (const XMLNodeList& nlist) +ProcessorBox::paste_processors (boost::shared_ptr before) +{ + + if (_rr_selection.processors.empty()) { + return; + } + + paste_processor_state (_rr_selection.processors.get_node().children(), before); +} + +void +ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr p) { XMLNodeConstIterator niter; list > copies; - cerr << "Pasting processor selection containing " << nlist.size() << endl; - if (nlist.empty()) { return; } for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - cerr << "try using " << (*niter)->name() << endl; + XMLProperty const * type = (*niter)->property ("type"); assert (type); boost::shared_ptr p; try { - if (type->value() == "send") { + if (type->value() == "meter" || + type->value() == "main-outs" || + type->value() == "amp" || + type->value() == "intsend" || type->value() == "intreturn") { + /* do not paste meter, main outs, amp or internal send/returns */ + continue; + + } else if (type->value() == "send") { + XMLNode n (**niter); Send::make_unique (n, _session); p.reset (new Send (_session, _route->mute_master(), n)); - } else if (type->value() == "meter") { - p = _route->shared_peak_meter(); + } else if (type->value() == "return") { - } else if (type->value() == "main-outs") { - /* do not copy-n-paste main outs */ - continue; - - } else if (type->value() == "amp") { - /* do not copy-n-paste amp */ - continue; - - } else if (type->value() == "intsend" || type->value() == "intreturn") { - /* do not copy-n-paste internal sends&returns */ - continue; - - } else if (type->value() == "listen") { - p.reset (new Delivery (_session, _route->mute_master(), **niter)); + XMLNode n (**niter); + Return::make_unique (n, _session); + p.reset (new Return (_session, **niter)); } else { + /* XXX its a bit limiting to assume that everything else + is a plugin. + */ p.reset (new PluginInsert (_session, **niter)); } copies.push_back (p); } + catch (...) { cerr << "plugin insert constructor failed\n"; } @@ -1185,7 +1240,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist) return; } - if (_route->add_processors (copies, _placement)) { + if (_route->add_processors (copies, p)) { string msg = _( "Copying the set of processors on the clipboard failed,\n\ @@ -1249,22 +1304,32 @@ ProcessorBox::clear_processors () string prompt; vector choices; - if (boost::dynamic_pointer_cast(_route) != 0) { - if (_placement == PreFader) { - prompt = _("Do you really want to remove all pre-fader processors from this track?\n" - "(this cannot be undone)"); - } else { - prompt = _("Do you really want to remove all post-fader processors from this track?\n" - "(this cannot be undone)"); - } + prompt = string_compose (_("Do you really want to remove all processors from %1?\n" + "(this cannot be undone)"), _route->name()); + + choices.push_back (_("Cancel")); + choices.push_back (_("Yes, remove them all")); + + Gtkmm2ext::Choice prompter (prompt, choices); + + if (prompter.run () == 1) { + _route->clear_processors (PreFader); + _route->clear_processors (PostFader); + } +} + +void +ProcessorBox::clear_processors (Placement p) +{ + string prompt; + vector choices; + + if (p == PreFader) { + prompt = string_compose (_("Do you really want to remove all pre-fader processors from %1?\n" + "(this cannot be undone)"), _route->name()); } else { - if (_placement == PreFader) { - prompt = _("Do you really want to remove all pre-fader processors from this bus?\n" - "(this cannot be undone)"); - } else { - prompt = _("Do you really want to remove all post-fader processors from this bus?\n" - "(this cannot be undone)"); - } + prompt = string_compose (_("Do you really want to remove all post-fader processors from %1?\n" + "(this cannot be undone)"), _route->name()); } choices.push_back (_("Cancel")); @@ -1273,7 +1338,7 @@ ProcessorBox::clear_processors () Gtkmm2ext::Choice prompter (prompt, choices); if (prompter.run () == 1) { - _route->clear_processors (_placement); + _route->clear_processors (p); } } @@ -1426,8 +1491,12 @@ ProcessorBox::register_actions () sigc::ptr_fun (ProcessorBox::rb_choose_return)); ActionManager::jack_sensitive_actions.push_back (act); - ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"), + ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear (all)"), sigc::ptr_fun (ProcessorBox::rb_clear)); + ActionManager::register_action (popup_act_grp, X_("clear_pre"), _("Clear (pre-fader)"), + sigc::ptr_fun (ProcessorBox::rb_clear_pre)); + ActionManager::register_action (popup_act_grp, X_("clear_post"), _("Clear (post-fader)"), + sigc::ptr_fun (ProcessorBox::rb_clear_post)); /* standard editing stuff */ act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"), @@ -1517,6 +1586,28 @@ ProcessorBox::rb_clear () _current_processor_box->clear_processors (); } + +void +ProcessorBox::rb_clear_pre () +{ + if (_current_processor_box == 0) { + return; + } + + _current_processor_box->clear_processors (PreFader); +} + + +void +ProcessorBox::rb_clear_post () +{ + if (_current_processor_box == 0) { + return; + } + + _current_processor_box->clear_processors (PostFader); +} + void ProcessorBox::rb_cut () { diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index 76fabe8d39..5dfbce7789 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -131,7 +131,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject Gtk::ScrolledWindow processor_scroller; void object_drop (const std::list >&, Gtk::TreeView*, - Glib::RefPtr& context); + int x, int y, Glib::RefPtr& context); Width _width; @@ -185,21 +185,27 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject void all_plugins_active(bool state); void ab_plugins (); + typedef std::vector > ProcSelection; + + void cut_processors (const ProcSelection&); void cut_processors (); + void copy_processors (const ProcSelection&); void copy_processors (); - void paste_processors (); + void delete_processors (const ProcSelection&); void delete_processors (); + void paste_processors (); + void paste_processors (boost::shared_ptr before); + void delete_dragged_processors (const std::list >&); void clear_processors (); + void clear_processors (ARDOUR::Placement); void rename_processors (); - typedef std::vector > ProcSelection; - void for_selected_processors (void (ProcessorBox::*pmf)(boost::shared_ptr)); void get_selected_processors (ProcSelection&); static Glib::RefPtr paste_action; - void paste_processor_state (const XMLNodeList&); + void paste_processor_state (const XMLNodeList&, boost::shared_ptr); void activate_processor (boost::shared_ptr); void deactivate_processor (boost::shared_ptr); @@ -218,6 +224,8 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject static void rb_choose_send (); static void rb_choose_return (); static void rb_clear (); + static void rb_clear_pre (); + static void rb_clear_post (); static void rb_cut (); static void rb_copy (); static void rb_paste (); diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h index 430f54d46d..ff985c6e79 100644 --- a/libs/ardour/ardour/io_processor.h +++ b/libs/ardour/ardour/io_processor.h @@ -66,6 +66,7 @@ class IOProcessor : public Processor void set_output (boost::shared_ptr); void silence (nframes_t nframes); + void disconnect (); virtual bool feeds (boost::shared_ptr other) const; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 7a44cb454c..8433038aed 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -205,9 +205,10 @@ class Route : public SessionObject, public AutomatableControls int add_processor (boost::shared_ptr, Placement placement, ProcessorStreams* err = 0); int add_processor (boost::shared_ptr, ProcessorList::iterator iter, ProcessorStreams* err = 0); - int add_processors (const ProcessorList&, Placement placement, ProcessorStreams* err = 0); + int add_processors (const ProcessorList&, boost::shared_ptr before, ProcessorStreams* err = 0); int add_processors (const ProcessorList&, ProcessorList::iterator iter, ProcessorStreams* err = 0); int remove_processor (boost::shared_ptr, ProcessorStreams* err = 0); + int remove_processors (const ProcessorList&, ProcessorStreams* err = 0); int reorder_processors (const ProcessorList& new_order, ProcessorStreams* err = 0); void disable_processors (Placement); void disable_processors (); diff --git a/libs/ardour/io_processor.cc b/libs/ardour/io_processor.cc index 87d679bbac..ebffd31028 100644 --- a/libs/ardour/io_processor.cc +++ b/libs/ardour/io_processor.cc @@ -265,3 +265,15 @@ IOProcessor::feeds (boost::shared_ptr other) const { return _output && _output->connected_to (other->input()); } + +void +IOProcessor::disconnect () +{ + if (_input) { + _input->disconnect (this); + } + + if (_output) { + _output->disconnect (this); + } +} diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index cc90a855a5..216c199041 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -826,28 +826,15 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter } int -Route::add_processors (const ProcessorList& others, Placement placement, ProcessorStreams* err) +Route::add_processors (const ProcessorList& others, boost::shared_ptr before, ProcessorStreams* err) { ProcessorList::iterator loc; - if (placement == PreFader) { - /* generic pre-fader: insert immediately before the amp */ - loc = find(_processors.begin(), _processors.end(), _amp); - } else { - /* generic post-fader: insert at end */ - loc = _processors.end(); - if (!_processors.empty()) { - /* check for invisible processors stacked at the end and leave them there */ - ProcessorList::iterator p; - p = _processors.end(); - --p; - cerr << "Let's check " << (*p)->name() << " vis ? " << (*p)->visible() << endl; - while (!(*p)->visible() && p != _processors.begin()) { - --p; - } - ++p; - loc = p; - } + if (before) { + loc = find(_processors.begin(), _processors.end(), before); + } else { + /* nothing specified - at end but before main outs */ + loc = find (_processors.begin(), _processors.end(), _main_outs); } return add_processors (others, loc, err); @@ -893,9 +880,11 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter if ((pi = boost::dynamic_pointer_cast(*i)) != 0) { pi->set_count (1); - ChanCount m = max(pi->input_streams(), pi->output_streams()); - if (m > potential_max_streams) + ChanCount m = max (pi->input_streams(), pi->output_streams()); + + if (m > potential_max_streams) { potential_max_streams = m; + } } _processors.insert (iter, *i); @@ -1067,26 +1056,43 @@ Route::clear_processors (Placement p) Glib::RWLock::WriterLock lm (_processor_lock); ProcessorList new_list; ProcessorStreams err; + bool seen_amp = false; - ProcessorList::iterator amp_loc = find(_processors.begin(), _processors.end(), _amp); - if (p == PreFader) { - // Get rid of PreFader processors - for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) { - (*i)->drop_references (); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + + if (*i == _amp) { + seen_amp = true; } - // Keep the rest - for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) { + + if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs) { + + /* you can't remove these */ + new_list.push_back (*i); - } - } else { - // Keep PreFader processors - for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) { - new_list.push_back (*i); - } - new_list.push_back (_amp); - // Get rid of PostFader processors - for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) { - (*i)->drop_references (); + + } else { + if (seen_amp) { + + switch (p) { + case PreFader: + new_list.push_back (*i); + break; + case PostFader: + (*i)->drop_references (); + break; + } + + } else { + + switch (p) { + case PreFader: + (*i)->drop_references (); + break; + case PostFader: + new_list.push_back (*i); + break; + } + } } } @@ -1192,6 +1198,99 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream return 0; } +int +Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* err) +{ + ProcessorList deleted; + ProcessorList as_we_were; + + if (!_session.engine().connected()) { + return 1; + } + + processor_max_streams.reset(); + + { + Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorList::iterator i; + boost::shared_ptr processor; + + as_we_were = _processors; + + for (i = _processors.begin(); i != _processors.end(); ) { + + processor = *i; + + /* these can never be removed */ + + if (processor == _amp || processor == _meter || processor == _main_outs) { + ++i; + continue; + } + + /* see if its in the list of processors to delete */ + + if (find (to_be_deleted.begin(), to_be_deleted.end(), processor) == to_be_deleted.end()) { + ++i; + continue; + } + + /* stop IOProcessors that send to JACK ports + from causing noise as a result of no longer being + run. + */ + + boost::shared_ptr iop; + + if ((iop = boost::dynamic_pointer_cast (processor)) != 0) { + iop->disconnect (); + } + + deleted.push_back (processor); + i = _processors.erase (i); + } + + if (deleted.empty()) { + /* none of those in the requested list were found */ + return 0; + } + + _output->set_user_latency (0); + + if (configure_processors_unlocked (err)) { + /* get back to where we where */ + _processors = as_we_were; + /* we know this will work, because it worked before :) */ + configure_processors_unlocked (0); + return -1; + } + + _have_internal_generator = false; + + for (i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr pi; + + if ((pi = boost::dynamic_pointer_cast(*i)) != 0) { + if (pi->is_generator()) { + _have_internal_generator = true; + break; + } + } + } + } + + /* now try to do what we need to so that those that were removed will be deleted */ + + for (ProcessorList::iterator i = deleted.begin(); i != deleted.end(); ++i) { + (*i)->drop_references (); + } + + processors_changed (); /* EMIT SIGNAL */ + + return 0; +} + + int Route::configure_processors (ProcessorStreams* err) { diff --git a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h index 5464920a59..6295377672 100644 --- a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h +++ b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h @@ -91,7 +91,7 @@ class DnDTreeView : public DnDTreeViewBase DnDTreeView() {} ~DnDTreeView() {} - sigc::signal&,Gtk::TreeView*,Glib::RefPtr&> signal_drop; + sigc::signal&,Gtk::TreeView*,int,int,Glib::RefPtr&> signal_drop; void on_drag_data_get(const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time) { if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") { @@ -126,7 +126,7 @@ class DnDTreeView : public DnDTreeViewBase } else if (selection_data.get_target() == object_type) { - end_object_drag (const_cast& > (context)); + end_object_drag (const_cast& > (context), x, y); } else { /* some kind of target type added by the app, which will be handled by a signal handler */ @@ -152,11 +152,11 @@ class DnDTreeView : public DnDTreeViewBase } private: - void end_object_drag (Glib::RefPtr& context) { + void end_object_drag (Glib::RefPtr& context, int x, int y) { std::list l; Gtk::TreeView* source; get_object_drag_data (l, &source); - signal_drop (l, source, context); + signal_drop (l, source, x, y, context); } };