most of the 2.X->3.0 commit (up to rev 4299) except for gtk2_ardour/editor_canvas...
[ardour.git] / gtk2_ardour / processor_box.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <cmath>
21 #include <iostream>
22 #include <set>
23
24 #include <sigc++/bind.h>
25
26 #include <pbd/convert.h>
27
28 #include <glibmm/miscutils.h>
29
30 #include <gtkmm/messagedialog.h>
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/choice.h>
35 #include <gtkmm2ext/utils.h>
36 #include <gtkmm2ext/stop_signal.h>
37 #include <gtkmm2ext/doi.h>
38 #include <gtkmm2ext/window_title.h>
39
40 #include <ardour/ardour.h>
41 #include <ardour/session.h>
42 #include <ardour/audioengine.h>
43 #include <ardour/route.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audio_diskstream.h>
46 #include <ardour/send.h>
47 #include <ardour/plugin_insert.h>
48 #include <ardour/port_insert.h>
49 #include <ardour/ladspa_plugin.h>
50 #include <ardour/profile.h>
51
52 #include "ardour_ui.h"
53 #include "ardour_dialog.h"
54 #include "public_editor.h"
55 #include "processor_box.h"
56 #include "keyboard.h"
57 #include "plugin_selector.h"
58 #include "route_processor_selection.h"
59 #include "mixer_ui.h"
60 #include "actions.h"
61 #include "plugin_ui.h"
62 #include "io_selector.h"
63 #include "utils.h"
64 #include "gui_thread.h"
65
66 #include "i18n.h"
67
68 #ifdef HAVE_AUDIOUNITS
69 class AUPluginUI;
70 #endif
71
72 using namespace sigc;
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace Gtk;
76 using namespace Glib;
77 using namespace Gtkmm2ext;
78
79 ProcessorBox* ProcessorBox::_current_processor_box = 0;
80 RefPtr<Action> ProcessorBox::paste_action;
81 bool ProcessorBox::get_colors = true;
82 Gdk::Color* ProcessorBox::active_processor_color;
83 Gdk::Color* ProcessorBox::inactive_processor_color;
84
85 ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, 
86                             RouteRedirectSelection & rsel, bool owner_is_mixer)
87         : _session(sess), 
88           _owner_is_mixer (owner_is_mixer), 
89           _placement(pcmnt), 
90           _plugin_selector(plugsel),
91           _rr_selection(rsel)
92 {
93         if (get_colors) {
94                 active_processor_color = new Gdk::Color;
95                 inactive_processor_color = new Gdk::Color;
96                 set_color (*active_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_ACTIVE, false ));
97                 set_color (*inactive_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_NORMAL, false ));
98                 get_colors = false;
99         }
100
101         _width = Wide;
102         processor_menu = 0;
103         send_action_menu = 0;
104         processor_drag_in_progress = false;
105         no_processor_redisplay = false;
106         ignore_delete = false;
107
108         model = ListStore::create(columns);
109
110         RefPtr<TreeSelection> selection = processor_display.get_selection();
111         selection->set_mode (Gtk::SELECTION_MULTIPLE);
112         selection->signal_changed().connect (mem_fun (*this, &ProcessorBox::selection_changed));
113
114         processor_display.set_model (model);
115         processor_display.append_column (X_("notshown"), columns.text);
116         processor_display.set_name ("ProcessorSelector");
117         processor_display.set_headers_visible (false);
118         processor_display.set_reorderable (true);
119         processor_display.set_size_request (-1, 40);
120         processor_display.get_column(0)->set_sizing(TREE_VIEW_COLUMN_FIXED);
121         processor_display.get_column(0)->set_fixed_width(48);
122         processor_display.add_object_drag (columns.processor.index(), "processors");
123         processor_display.signal_drop.connect (mem_fun (*this, &ProcessorBox::object_drop));
124
125         TreeViewColumn* name_col = processor_display.get_column(0);
126         CellRendererText* renderer = dynamic_cast<CellRendererText*>(processor_display.get_column_cell_renderer (0));
127         name_col->add_attribute(renderer->property_foreground_gdk(), columns.color);
128
129         processor_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
130         
131         model->signal_row_deleted().connect (mem_fun (*this, &ProcessorBox::row_deleted));
132
133         processor_scroller.add (processor_display);
134         processor_eventbox.add (processor_scroller);
135         
136         processor_scroller.set_size_request (-1, 40);
137
138         pack_start (processor_eventbox, true, true);
139
140         processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
141
142         processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
143         processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
144 }
145
146 ProcessorBox::~ProcessorBox ()
147 {
148 }
149
150 void
151 ProcessorBox::set_route (boost::shared_ptr<Route> r)
152 {
153         connections.clear ();
154
155         _route = r;
156
157         connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
158         connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
159
160         redisplay_processors ();
161 }
162
163 void
164 ProcessorBox::route_going_away ()
165 {
166         /* don't keep updating display as processors are deleted */
167         no_processor_redisplay = true;
168 }
169
170
171 void
172 ProcessorBox::object_drop (const list<boost::shared_ptr<Processor> >& procs)
173 {
174         paste_processor_list (procs);
175 }
176
177 void
178 ProcessorBox::update()
179 {
180         redisplay_processors ();
181 }
182
183
184 void
185 ProcessorBox::set_width (Width w)
186 {
187         if (_width == w) {
188                 return;
189         }
190         _width = w;
191
192         redisplay_processors ();
193 }
194
195 void
196 ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
197 {
198         boost::shared_ptr<Send> send;
199         boost::shared_ptr<PortInsert> port_insert;
200
201         if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
202
203                 PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
204                 port_insert->set_gui (0);
205                 delete io_selector;
206
207         } else if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
208                 SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
209                 send->set_gui (0);
210                 delete sui;
211         }
212 }
213
214 void 
215 ProcessorBox::build_send_action_menu ()
216
217 {
218         using namespace Menu_Helpers;
219
220         send_action_menu = new Menu;
221         send_action_menu->set_name ("ArdourContextMenu");
222         MenuList& items = send_action_menu->items();
223
224         items.push_back (MenuElem (_("New send"), mem_fun(*this, &ProcessorBox::new_send)));
225         items.push_back (MenuElem (_("Show send controls"), mem_fun(*this, &ProcessorBox::show_send_controls)));
226 }
227
228 void
229 ProcessorBox::show_send_controls ()
230
231 {
232 }
233
234 void
235 ProcessorBox::new_send ()
236
237 {
238 }
239
240 void
241 ProcessorBox::show_processor_menu (gint arg)
242 {
243         if (processor_menu == 0) {
244                 processor_menu = build_processor_menu ();
245         }
246
247         Gtk::MenuItem* plugin_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/processormenu/newplugin"));
248
249         if (plugin_menu_item) {
250                 plugin_menu_item->set_submenu (_plugin_selector.plugin_menu());
251         }
252
253         paste_action->set_sensitive (!_rr_selection.processors.empty());
254
255         processor_menu->popup (1, arg);
256 }
257
258 void
259 ProcessorBox::processor_drag_begin (GdkDragContext *context)
260 {
261         processor_drag_in_progress = true;
262 }
263
264 void
265 ProcessorBox::processor_drag_end (GdkDragContext *context)
266 {
267         processor_drag_in_progress = false;
268 }
269
270 bool
271 ProcessorBox::processor_button_press_event (GdkEventButton *ev)
272 {
273         TreeIter iter;
274         TreeModel::Path path;
275         TreeViewColumn* column;
276         int cellx;
277         int celly;
278         boost::shared_ptr<Processor> processor;
279         int ret = false;
280         bool selected = false;
281
282         if (processor_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
283                 if ((iter = model->get_iter (path))) {
284                         processor = (*iter)[columns.processor];
285                         selected = processor_display.get_selection()->is_selected (iter);
286                 }
287                 
288         }
289
290         if (processor && (Keyboard::is_edit_event (ev) || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS))) {
291                 
292                 if (_session.engine().connected()) {
293                         /* XXX giving an error message here is hard, because we may be in the midst of a button press */
294                         edit_processor (processor);
295                 }
296                 ret = true;
297                 
298         } else if (processor && ev->button == 1 && selected) {
299
300                 // this is purely informational but necessary
301                 ProcessorSelected (processor); // emit
302
303         } else if (!processor && ev->button == 1 && ev->type == GDK_2BUTTON_PRESS) {
304
305                 choose_plugin ();
306                 _plugin_selector.show_manager ();
307         }
308
309         
310         return ret;
311 }
312
313 bool
314 ProcessorBox::processor_button_release_event (GdkEventButton *ev)
315 {
316         TreeIter iter;
317         TreeModel::Path path;
318         TreeViewColumn* column;
319         int cellx;
320         int celly;
321         boost::shared_ptr<Processor> processor;
322         int ret = false;
323
324
325         if (processor_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
326                 if ((iter = model->get_iter (path))) {
327                         processor = (*iter)[columns.processor];
328                 }
329         }
330
331         if (processor && Keyboard::is_delete_event (ev)) {
332                 
333                 Glib::signal_idle().connect (bind (mem_fun(*this, &ProcessorBox::idle_delete_processor), boost::weak_ptr<Processor>(processor)));
334                 ret = true;
335                 
336         } else if (Keyboard::is_context_menu_event (ev)) {
337
338                 show_processor_menu(ev->time);
339                 ret = true;
340
341         } else if (processor && Keyboard::is_button2_event (ev) && (Keyboard::no_modifier_keys_pressed (ev) && ((ev->state & Gdk::BUTTON2_MASK) == Gdk::BUTTON2_MASK))) {
342                 
343                 /* button2-click with no modifiers */
344
345                 processor->set_active (!processor->active());
346                 ret = true;
347
348         } 
349
350         return ret;
351 }
352
353 Menu *
354 ProcessorBox::build_processor_menu ()
355 {
356         processor_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/processormenu") );
357         processor_menu->set_name ("ArdourContextMenu");
358
359         show_all_children();
360
361         return processor_menu;
362 }
363
364 void
365 ProcessorBox::selection_changed ()
366 {
367         bool sensitive = (processor_display.get_selection()->count_selected_rows()) ? true : false;
368         ActionManager::set_sensitive (ActionManager::plugin_selection_sensitive_actions, sensitive);
369 }
370
371 void
372 ProcessorBox::select_all_processors ()
373 {
374         processor_display.get_selection()->select_all();
375 }
376
377 void
378 ProcessorBox::deselect_all_processors ()
379 {
380         processor_display.get_selection()->unselect_all();
381 }
382
383 void
384 ProcessorBox::choose_plugin ()
385 {
386         _plugin_selector.set_interested_object (*this);
387 }
388
389 void
390 ProcessorBox::use_plugins (const SelectedPlugins& plugins)
391 {
392         for (SelectedPlugins::const_iterator p = plugins.begin(); p != plugins.end(); ++p) {
393
394                 boost::shared_ptr<Processor> processor (new PluginInsert (_session, *p, _placement));
395
396                 Route::ProcessorStreams err_streams;
397
398                 if (Config->get_new_plugins_active()) {
399                         processor->set_active (true);
400                 }
401                 
402                 if (_route->add_processor (processor, &err_streams)) {
403                         weird_plugin_dialog (**p, err_streams, _route);
404                         // XXX SHAREDPTR delete plugin here .. do we even need to care? 
405                 } else {
406                         
407                         if (Profile->get_sae()) {
408                                 processor->set_active (true);
409                         }
410                         processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
411                 }
412         }
413 }
414
415 void
416 ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, boost::shared_ptr<IO> io)
417 {
418         ArdourDialog dialog (_("ardour: weird plugin dialog"));
419         Label label;
420
421         /* i hate this kind of code */
422
423         if (streams.count > p.get_info()->n_inputs) {
424                 label.set_text (string_compose (_(
425 "You attempted to add a plugin (%1).\n"
426 "The plugin has %2 inputs\n"
427 "but at the processorion point, there are\n"
428 "%3 active signal streams.\n"
429 "\n"
430 "This makes no sense - you are throwing away\n"
431 "part of the signal."),
432                                          p.name(),
433                                          p.get_info()->n_inputs.n_total(),
434                                          streams.count.n_total()));
435         } else if (streams.count < p.get_info()->n_inputs) {
436                 label.set_text (string_compose (_(
437 "You attempted to add a plugin (%1).\n"
438 "The plugin has %2 inputs\n"
439 "but at the processorion point there are\n"
440 "only %3 active signal streams.\n"
441 "\n"
442 "This makes no sense - unless the plugin supports\n"
443 "side-chain inputs. A future version of Ardour will\n"
444 "support this type of configuration."),
445                                          p.name(),
446                                          p.get_info()->n_inputs.n_total(),
447                                          streams.count.n_total()));
448         } else {
449                 label.set_text (string_compose (_(
450 "You attempted to add a plugin (%1).\n"
451 "\n"
452 "The I/O configuration doesn't make sense:\n"
453 "\n" 
454 "The plugin has %2 inputs and %3 outputs.\n"
455 "The track/bus has %4 inputs and %5 outputs.\n"
456 "The processorion point, has %6 active signals.\n"
457 "\n"
458 "Ardour does not understand what to do in such situations.\n"),
459                                          p.name(),
460                                          p.get_info()->n_inputs.n_total(),
461                                          p.get_info()->n_outputs.n_total(),
462                                          io->n_inputs().n_total(),
463                                          io->n_outputs().n_total(),
464                                          streams.count.n_total()));
465         }
466
467         dialog.get_vbox()->pack_start (label);
468         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
469
470         dialog.set_name (X_("PluginIODialog"));
471         dialog.set_position (Gtk::WIN_POS_MOUSE);
472         dialog.set_modal (true);
473         dialog.show_all ();
474
475         dialog.run ();
476 }
477
478 void
479 ProcessorBox::choose_insert ()
480 {
481         boost::shared_ptr<Processor> processor (new PortInsert (_session, _placement));
482         processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
483         _route->add_processor (processor);
484 }
485
486 void
487 ProcessorBox::choose_send ()
488 {
489         boost::shared_ptr<Send> send (new Send (_session, _placement));
490         //send->set_default_type(_route->default_type());
491
492         ChanCount outs;
493
494         /* make an educated guess at the initial number of outputs for the send */
495
496         if (_session.master_out()) {
497                 outs = _session.master_out()->n_outputs();
498         } else {
499                 outs = _route->n_outputs();
500         }
501
502         /* XXX need processor lock on route */
503
504         try {
505                 send->io()->ensure_io (ChanCount::ZERO, outs, false, this);
506         } catch (AudioEngine::PortRegistrationFailure& err) {
507                 error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
508                 return;
509         }
510         
511         /* let the user adjust the output setup (number and connections) before passing
512            it along to the Route
513         */
514         
515         IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
516
517         ios->show_all ();
518
519         boost::shared_ptr<Processor> r = boost::static_pointer_cast<Processor>(send);
520         
521         ios->selector().Finished.connect (bind (mem_fun(*this, &ProcessorBox::send_io_finished), boost::weak_ptr<Processor>(r), ios));
522 }
523
524 void
525 ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor> weak_processor, IOSelectorWindow* ios)
526 {
527         boost::shared_ptr<Processor> processor (weak_processor.lock());
528
529         if (!processor) {
530                 return;
531         }
532
533         switch (r) {
534         case IOSelector::Cancelled:
535                 // processor will go away when all shared_ptrs to it vanish
536                 break;
537
538         case IOSelector::Accepted:
539                 _route->add_processor (processor);
540                 if (Profile->get_sae()) {
541                         processor->set_active (true);
542                 }
543                 break;
544         }
545
546         delete_when_idle (ios);
547 }
548
549 void
550 ProcessorBox::redisplay_processors ()
551 {
552         ENSURE_GUI_THREAD (mem_fun(*this, &ProcessorBox::redisplay_processors));
553
554         if (no_processor_redisplay) {
555                 return;
556         }
557         
558         ignore_delete = true;
559         model->clear ();
560         ignore_delete = false;
561
562         processor_active_connections.clear ();
563         processor_name_connections.clear ();
564
565         void (ProcessorBox::*method)(boost::shared_ptr<Processor>) = &ProcessorBox::add_processor_to_display;
566         _route->foreach_processor (this, method);
567
568         switch (_placement) {
569         case PreFader:
570                 build_processor_tooltip(processor_eventbox, _("Pre-fader inserts, sends & plugins:"));
571                 break;
572         case PostFader:
573                 build_processor_tooltip(processor_eventbox, _("Post-fader inserts, sends & plugins:"));
574                 break;
575         }
576 }
577
578 void
579 ProcessorBox::add_processor_to_display (boost::shared_ptr<Processor> processor)
580 {
581         if (processor->placement() != _placement) {
582                 return;
583         }
584         
585         Gtk::TreeModel::Row row = *(model->append());
586         row[columns.text] = processor_name (processor);
587         row[columns.processor] = processor;
588
589         show_processor_active (processor);
590
591         processor_active_connections.push_back (processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor))));
592         processor_name_connections.push_back (processor->NameChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_name), boost::weak_ptr<Processor>(processor))));
593 }
594
595 string
596 ProcessorBox::processor_name (boost::weak_ptr<Processor> weak_processor)
597 {
598         boost::shared_ptr<Processor> processor (weak_processor.lock());
599
600         if (!processor) {
601                 return string();
602         }
603
604         boost::shared_ptr<Send> send;
605         string name_display;
606
607         if (!processor->active()) {
608                 name_display = " (";
609         }
610
611         if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
612
613                 name_display += '>';
614
615                 /* grab the send name out of its overall name */
616
617                 string::size_type lbracket, rbracket;
618                 lbracket = send->name().find ('[');
619                 rbracket = send->name().find (']');
620
621                 switch (_width) {
622                 case Wide:
623                         name_display += send->name().substr (lbracket+1, lbracket-rbracket-1);
624                         break;
625                 case Narrow:
626                         name_display += PBD::short_version (send->name().substr (lbracket+1, lbracket-rbracket-1), 4);
627                         break;
628                 }
629
630         } else {
631
632                 switch (_width) {
633                 case Wide:
634                         name_display += processor->name();
635                         break;
636                 case Narrow:
637                         name_display += PBD::short_version (processor->name(), 5);
638                         break;
639                 }
640
641         }
642
643         if (!processor->active()) {
644                 name_display += ')';
645         }
646
647         return name_display;
648 }
649
650 void
651 ProcessorBox::build_processor_tooltip (EventBox& box, string start)
652 {
653         string tip(start);
654
655         Gtk::TreeModel::Children children = model->children();
656         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
657                 Gtk::TreeModel::Row row = *iter;
658                 tip += '\n';
659                 tip += row[columns.text];
660         }
661         ARDOUR_UI::instance()->tooltips().set_tip (box, tip);
662 }
663
664 void
665 ProcessorBox::show_processor_name (boost::weak_ptr<Processor> processor)
666 {
667         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ProcessorBox::show_processor_name), processor));
668         show_processor_active (processor);
669 }
670
671 void
672 ProcessorBox::show_processor_active (boost::weak_ptr<Processor> weak_processor)
673 {
674         boost::shared_ptr<Processor> processor (weak_processor.lock());
675         
676         if (!processor) {
677                 return;
678         }
679
680         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ProcessorBox::show_processor_active), weak_processor));
681         
682         Gtk::TreeModel::Children children = model->children();
683         Gtk::TreeModel::Children::iterator iter = children.begin();
684
685         while (iter != children.end()) {
686
687                 boost::shared_ptr<Processor> r = (*iter)[columns.processor];
688
689                 if (r == processor) {
690                         (*iter)[columns.text] = processor_name (r);
691                         
692                         if (processor->active()) {
693                                 (*iter)[columns.color] = *active_processor_color;
694                         } else {
695                                 (*iter)[columns.color] = *inactive_processor_color;
696                         }
697                         break;
698                 }
699
700                 iter++;
701         }
702 }
703
704 void
705 ProcessorBox::row_deleted (const Gtk::TreeModel::Path& path)
706 {
707         if (!ignore_delete) {
708                 compute_processor_sort_keys ();
709         }
710 }
711
712 void
713 ProcessorBox::compute_processor_sort_keys ()
714 {
715         uint32_t sort_key = 0;
716         Gtk::TreeModel::Children children = model->children();
717
718         for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
719                 boost::shared_ptr<Processor> r = (*iter)[columns.processor];
720                 r->set_sort_key (sort_key);
721                 sort_key++;
722         }
723
724         if (_route->sort_processors ()) {
725
726                 redisplay_processors ();
727
728                 /* now tell them about the problem */
729
730                 ArdourDialog dialog (_("ardour: weird plugin dialog"));
731                 Label label;
732
733                 label.set_text (_("\
734 You cannot reorder this set of processors\n\
735 in that way because the inputs and\n\
736 outputs do not work correctly."));
737
738                 dialog.get_vbox()->pack_start (label);
739                 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
740
741                 dialog.set_name (X_("PluginIODialog"));
742                 dialog.set_position (Gtk::WIN_POS_MOUSE);
743                 dialog.set_modal (true);
744                 dialog.show_all ();
745
746                 dialog.run ();
747         }
748 }
749
750 void
751 ProcessorBox::rename_processors ()
752 {
753         vector<boost::shared_ptr<Processor> > to_be_renamed;
754         
755         get_selected_processors (to_be_renamed);
756
757         if (to_be_renamed.empty()) {
758                 return;
759         }
760
761         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
762                 rename_processor (*i);
763         }
764 }
765
766 void
767 ProcessorBox::cut_processors ()
768 {
769         vector<boost::shared_ptr<Processor> > to_be_removed;
770         XMLNode* node = new XMLNode (X_("cut"));
771
772         get_selected_processors (to_be_removed);
773
774         if (to_be_removed.empty()) {
775                 return;
776         }
777
778         no_processor_redisplay = true;
779         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
780                 // Do not cut inserts
781                 if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
782                     (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
783
784                         void* gui = (*i)->get_gui ();
785                 
786                         if (gui) {
787                                 static_cast<Gtk::Widget*>(gui)->hide ();
788                         }
789                         
790                         XMLNode& child ((*i)->get_state());
791
792                         if (_route->remove_processor (*i) == 0) {
793                                 /* success */
794                                 node->add_child_nocopy (child);
795                         } else {
796                                 delete &child;
797                         }
798                 } 
799         }
800
801         _rr_selection.set (node);
802
803         no_processor_redisplay = false;
804         redisplay_processors ();
805 }
806
807 void
808 ProcessorBox::copy_processors ()
809 {
810         vector<boost::shared_ptr<Processor> > to_be_copied;
811         XMLNode* node = new XMLNode (X_("copy"));
812
813         get_selected_processors (to_be_copied);
814
815         if (to_be_copied.empty()) {
816                 return;
817         }
818
819         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
820                 // Do not copy inserts
821                 if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
822                     (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
823                         node->add_child_nocopy ((*i)->get_state());
824                 }
825         }
826
827         _rr_selection.set (node);
828 }
829
830 void
831 ProcessorBox::delete_processors ()
832 {
833         vector<boost::shared_ptr<Processor> > to_be_deleted;
834         
835         get_selected_processors (to_be_deleted);
836
837         if (to_be_deleted.empty()) {
838                 return;
839         }
840
841         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
842                 
843                 void* gui = (*i)->get_gui ();
844                 
845                 if (gui) {
846                         static_cast<Gtk::Widget*>(gui)->hide ();
847                 }
848
849                 _route->remove_processor(*i);
850         }
851
852         no_processor_redisplay = false;
853         redisplay_processors ();
854 }
855
856 gint
857 ProcessorBox::idle_delete_processor (boost::weak_ptr<Processor> weak_processor)
858 {
859         boost::shared_ptr<Processor> processor (weak_processor.lock());
860
861         if (!processor) {
862                 return false;
863         }
864
865         /* NOT copied to _mixer.selection() */
866
867         no_processor_redisplay = true;
868         _route->remove_processor (processor);
869         no_processor_redisplay = false;
870         redisplay_processors ();
871
872         return false;
873 }
874
875 void
876 ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
877 {
878         ArdourPrompter name_prompter (true);
879         string result;
880         name_prompter.set_prompt (_("rename processor"));
881         name_prompter.set_initial_text (processor->name());
882         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
883         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
884         name_prompter.show_all ();
885
886         switch (name_prompter.run ()) {
887
888         case Gtk::RESPONSE_ACCEPT:
889         name_prompter.get_result (result);
890         if (result.length()) {
891                         processor->set_name (result);
892                 }       
893                 break;
894         }
895
896         return;
897 }
898
899 void
900 ProcessorBox::paste_processors ()
901 {
902         if (_rr_selection.processors.empty()) {
903                 return;
904         }
905
906         cerr << "paste from node called " << _rr_selection.processors.get_node().name() << endl;
907
908         paste_processor_state (_rr_selection.processors.get_node());
909 }
910
911 void
912 ProcessorBox::paste_processor_list (const list<boost::shared_ptr<Processor> >& processors)
913 {
914         list<boost::shared_ptr<Processor> > copies;
915         
916         for (list<boost::shared_ptr<Processor> >::const_iterator i = processors.begin(); i != processors.end(); ++i) {
917                 
918                 boost::shared_ptr<Processor> copy = Processor::clone (*i);
919                 
920                 copy->set_placement (_placement);
921                 copies.push_back (copy);
922         }
923
924         if (_route->add_processors (copies)) {
925
926                 string msg = _(
927                         "Copying the set of processors on the clipboard failed,\n\
928 probably because the I/O configuration of the plugins\n\
929 could not match the configuration of this track.");
930                 MessageDialog am (msg);
931                 am.run ();
932         }
933 }
934
935 void
936 ProcessorBox::paste_processor_state (const XMLNode& node)
937 {
938         XMLNodeList nlist;
939         XMLNodeConstIterator niter;
940         list<boost::shared_ptr<Processor> > copies;
941
942         nlist = node.children();
943
944         cerr << "Pasting processor selection containing " << nlist.size() << endl;
945
946         if (nlist.empty()) {
947                 return;
948         }
949
950         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
951                 cerr << "try using " << (*niter)->name() << endl;
952                 try {
953                         copies.push_back (boost::shared_ptr<Processor> (new PluginInsert (_session, **niter)));
954                 }
955                 catch (...) {
956                         cerr << "plugin insert constructor failed\n";
957                 }
958         }
959
960         if (_route->add_processors (copies)) {
961
962                 string msg = _(
963                         "Copying the set of processors on the clipboard failed,\n\
964 probably because the I/O configuration of the plugins\n\
965 could not match the configuration of this track.");
966                 MessageDialog am (msg);
967                 am.run ();
968         }
969 }
970
971 void
972 ProcessorBox::activate_processor (boost::shared_ptr<Processor> r)
973 {
974         r->set_active (true);
975 }
976
977 void
978 ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
979 {
980         r->set_active (false);
981 }
982
983 void
984 ProcessorBox::get_selected_processors (vector<boost::shared_ptr<Processor> >& processors)
985 {
986     vector<Gtk::TreeModel::Path> pathlist = processor_display.get_selection()->get_selected_rows();
987  
988     for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
989             processors.push_back ((*(model->get_iter(*iter)))[columns.processor]);
990     }
991 }
992
993 void
994 ProcessorBox::for_selected_processors (void (ProcessorBox::*method)(boost::shared_ptr<Processor>))
995 {
996     vector<Gtk::TreeModel::Path> pathlist = processor_display.get_selection()->get_selected_rows();
997
998         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
999                 boost::shared_ptr<Processor> processor = (*(model->get_iter(*iter)))[columns.processor];
1000                 (this->*method)(processor);
1001         }
1002 }
1003
1004 void
1005 ProcessorBox::clone_processors ()
1006 {
1007         RouteSelection& routes (_rr_selection.routes);
1008
1009         if (!routes.empty()) {
1010                 if (_route->copy_processors (*routes.front(), _placement)) {
1011                         string msg = _(
1012 "Copying the set of processors on the clipboard failed,\n\
1013 probably because the I/O configuration of the plugins\n\
1014 could not match the configuration of this track.");
1015                         MessageDialog am (msg);
1016                         am.run ();
1017                 }
1018         }
1019 }
1020
1021 void
1022 ProcessorBox::all_processors_active (bool state)
1023 {
1024         _route->all_processors_active (_placement, state);
1025 }
1026
1027 void
1028 ProcessorBox::ab_plugins ()
1029 {
1030         _route->ab_plugins (ab_direction);
1031         ab_direction = !ab_direction;
1032 }
1033
1034
1035 void
1036 ProcessorBox::clear_processors ()
1037 {
1038         string prompt;
1039         vector<string> choices;
1040
1041         if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) {
1042                 if (_placement == PreFader) {
1043                         prompt = _("Do you really want to remove all pre-fader processors from this track?\n"
1044                                    "(this cannot be undone)");
1045                 } else {
1046                         prompt = _("Do you really want to remove all post-fader processors from this track?\n"
1047                                    "(this cannot be undone)");
1048                 }
1049         } else {
1050                 if (_placement == PreFader) {
1051                         prompt = _("Do you really want to remove all pre-fader processors from this bus?\n"
1052                                    "(this cannot be undone)");
1053                 } else {
1054                         prompt = _("Do you really want to remove all post-fader processors from this bus?\n"
1055                                    "(this cannot be undone)");
1056                 }
1057         }
1058
1059         choices.push_back (_("Cancel"));
1060         choices.push_back (_("Yes, remove them all"));
1061
1062         Gtkmm2ext::Choice prompter (prompt, choices);
1063
1064         if (prompter.run () == 1) {
1065                 _route->clear_processors (_placement);
1066         }
1067 }
1068
1069 void
1070 ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
1071 {
1072         boost::shared_ptr<Send> send;
1073         boost::shared_ptr<PluginInsert> plugin_insert;
1074         boost::shared_ptr<PortInsert> port_insert;
1075         Window* gidget = 0;
1076
1077         if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) {
1078
1079                 if (boost::dynamic_pointer_cast<AudioTrack> (_route)->freeze_state() == AudioTrack::Frozen) {
1080                         return;
1081                 }
1082         }
1083         
1084         if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
1085                 
1086                 if (!_session.engine().connected()) {
1087                         return;
1088                 }
1089
1090                 boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
1091                 
1092                 SendUIWindow *send_ui;
1093                 
1094                 if (send->get_gui() == 0) {
1095                         
1096                         send_ui = new SendUIWindow (send, _session);
1097
1098                         WindowTitle title(Glib::get_application_name());
1099                         title += send->name();
1100                         send_ui->set_title (title.get_string());
1101
1102                         send->set_gui (send_ui);
1103                         
1104                 } else {
1105                         send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
1106                 }
1107                 
1108                 gidget = send_ui;
1109                 
1110         } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
1111                 
1112                 PluginUIWindow *plugin_ui;
1113                 
1114                 /* these are both allowed to be null */
1115                 
1116                 Container* toplevel = get_toplevel();
1117                 Window* win = dynamic_cast<Gtk::Window*>(toplevel);
1118                 
1119                 if (plugin_insert->get_gui() == 0) {
1120                         
1121                         plugin_ui = new PluginUIWindow (win, plugin_insert);
1122                         
1123                         WindowTitle title(Glib::get_application_name());
1124                         title += generate_processor_title (plugin_insert);
1125                         plugin_ui->set_title (title.get_string());
1126                         
1127                         plugin_insert->set_gui (plugin_ui);
1128                         
1129                         // change window title when route name is changed
1130                         _route->NameChanged.connect (bind (mem_fun(*this, &ProcessorBox::route_name_changed), plugin_ui, boost::weak_ptr<PluginInsert> (plugin_insert)));
1131                         
1132                 } else {
1133                         plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
1134                         plugin_ui->set_parent (win);
1135                 }
1136                 
1137                 gidget = plugin_ui;
1138                 
1139         } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
1140                 
1141                 if (!_session.engine().connected()) {
1142                         MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible"));
1143                         msg.run ();
1144                         return;
1145                 }
1146                 
1147                 PortInsertWindow *io_selector;
1148                 
1149                 if (port_insert->get_gui() == 0) {
1150                         io_selector = new PortInsertWindow (_session, port_insert);
1151                         port_insert->set_gui (io_selector);
1152                         
1153                 } else {
1154                         io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
1155                 }
1156                 
1157                 gidget = io_selector;
1158         }
1159
1160         if (gidget) {
1161                 if (gidget->is_visible()) {
1162                         gidget->get_window()->raise ();
1163                 } else {
1164                         gidget->show_all ();
1165                         gidget->present ();
1166                 }
1167         }
1168 }
1169
1170 bool
1171 ProcessorBox::enter_box (GdkEventCrossing *ev, ProcessorBox* rb)
1172 {
1173         switch (ev->detail) {
1174         case GDK_NOTIFY_INFERIOR:
1175                 break;
1176
1177         case GDK_NOTIFY_VIRTUAL:
1178                 /* fallthru */
1179
1180         default:
1181                 _current_processor_box = rb;
1182         }
1183
1184         return false;
1185 }
1186
1187 void
1188 ProcessorBox::register_actions ()
1189 {
1190         Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("processormenu"));
1191         Glib::RefPtr<Action> act;
1192
1193         /* new stuff */
1194         ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin"),  sigc::ptr_fun (ProcessorBox::rb_choose_plugin));
1195
1196         act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),  sigc::ptr_fun (ProcessorBox::rb_choose_insert));
1197         ActionManager::jack_sensitive_actions.push_back (act);
1198         act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),  sigc::ptr_fun (ProcessorBox::rb_choose_send));
1199         ActionManager::jack_sensitive_actions.push_back (act);
1200
1201         ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),  sigc::ptr_fun (ProcessorBox::rb_clear));
1202
1203         /* standard editing stuff */
1204         act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),  sigc::ptr_fun (ProcessorBox::rb_cut));
1205         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1206         act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),  sigc::ptr_fun (ProcessorBox::rb_copy));
1207         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1208
1209         act = ActionManager::register_action (popup_act_grp, X_("delete"), _("Delete"),  sigc::ptr_fun (ProcessorBox::rb_delete));
1210         ActionManager::plugin_selection_sensitive_actions.push_back(act); // ??
1211
1212         paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),  sigc::ptr_fun (ProcessorBox::rb_paste));
1213         act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),  sigc::ptr_fun (ProcessorBox::rb_rename));
1214         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1215         ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),  sigc::ptr_fun (ProcessorBox::rb_select_all));
1216         ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),  sigc::ptr_fun (ProcessorBox::rb_deselect_all));
1217                 
1218         /* activation */
1219         act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),  sigc::ptr_fun (ProcessorBox::rb_activate));
1220         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1221         act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),  sigc::ptr_fun (ProcessorBox::rb_deactivate));
1222         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1223         ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),  sigc::ptr_fun (ProcessorBox::rb_activate_all));
1224         ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),  sigc::ptr_fun (ProcessorBox::rb_deactivate_all));
1225
1226         /* show editors */
1227         act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),  sigc::ptr_fun (ProcessorBox::rb_edit));
1228         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1229
1230         ActionManager::add_action_group (popup_act_grp);
1231
1232
1233 }
1234
1235 void
1236 ProcessorBox::rb_choose_plugin ()
1237 {
1238         if (_current_processor_box == 0) {
1239                 return;
1240         }
1241         _current_processor_box->choose_plugin ();
1242 }
1243
1244 void
1245 ProcessorBox::rb_choose_insert ()
1246 {
1247         if (_current_processor_box == 0) {
1248                 return;
1249         }
1250         _current_processor_box->choose_insert ();
1251 }
1252
1253 void
1254 ProcessorBox::rb_choose_send ()
1255 {
1256         if (_current_processor_box == 0) {
1257                 return;
1258         }
1259         _current_processor_box->choose_send ();
1260 }
1261
1262 void
1263 ProcessorBox::rb_clear ()
1264 {
1265         if (_current_processor_box == 0) {
1266                 return;
1267         }
1268
1269         _current_processor_box->clear_processors ();
1270 }
1271
1272 void
1273 ProcessorBox::rb_cut ()
1274 {
1275         if (_current_processor_box == 0) {
1276                 return;
1277         }
1278
1279         _current_processor_box->cut_processors ();
1280 }
1281
1282 void
1283 ProcessorBox::rb_delete ()
1284 {
1285         if (_current_processor_box == 0) {
1286                 return;
1287         }
1288
1289         _current_processor_box->delete_processors ();
1290 }
1291
1292 void
1293 ProcessorBox::rb_copy ()
1294 {
1295         if (_current_processor_box == 0) {
1296                 return;
1297         }
1298         _current_processor_box->copy_processors ();
1299 }
1300
1301 void
1302 ProcessorBox::rb_paste ()
1303 {
1304         if (_current_processor_box == 0) {
1305                 return;
1306         }
1307
1308         _current_processor_box->paste_processors ();
1309 }
1310
1311 void
1312 ProcessorBox::rb_rename ()
1313 {
1314         if (_current_processor_box == 0) {
1315                 return;
1316         }
1317         _current_processor_box->rename_processors ();
1318 }
1319
1320 void
1321 ProcessorBox::rb_select_all ()
1322 {
1323         if (_current_processor_box == 0) {
1324                 return;
1325         }
1326
1327         _current_processor_box->select_all_processors ();
1328 }
1329
1330 void
1331 ProcessorBox::rb_deselect_all ()
1332 {
1333         if (_current_processor_box == 0) {
1334                 return;
1335         }
1336
1337         _current_processor_box->deselect_all_processors ();
1338 }
1339
1340 void
1341 ProcessorBox::rb_activate ()
1342 {
1343         if (_current_processor_box == 0) {
1344                 return;
1345         }
1346
1347         _current_processor_box->for_selected_processors (&ProcessorBox::activate_processor);
1348 }
1349
1350 void
1351 ProcessorBox::rb_deactivate ()
1352 {
1353         if (_current_processor_box == 0) {
1354                 return;
1355         }
1356         _current_processor_box->for_selected_processors (&ProcessorBox::deactivate_processor);
1357 }
1358
1359 void
1360 ProcessorBox::rb_activate_all ()
1361 {
1362         if (_current_processor_box == 0) {
1363                 return;
1364         }
1365
1366         _current_processor_box->all_processors_active (true);
1367 }
1368
1369 void
1370 ProcessorBox::rb_deactivate_all ()
1371 {
1372         if (_current_processor_box == 0) {
1373                 return;
1374         }
1375         _current_processor_box->all_processors_active (false);
1376 }
1377
1378 void
1379 ProcessorBox::rb_edit ()
1380 {
1381         if (_current_processor_box == 0) {
1382                 return;
1383         }
1384
1385         _current_processor_box->for_selected_processors (&ProcessorBox::edit_processor);
1386 }
1387
1388 void
1389 ProcessorBox::route_name_changed (PluginUIWindow* plugin_ui, boost::weak_ptr<PluginInsert> wpi)
1390 {
1391         ENSURE_GUI_THREAD(bind (mem_fun (*this, &ProcessorBox::route_name_changed), plugin_ui, wpi));
1392
1393         boost::shared_ptr<PluginInsert> pi (wpi.lock());
1394
1395         if (pi) {
1396                 WindowTitle title(Glib::get_application_name());
1397                 title += generate_processor_title (pi);
1398                 plugin_ui->set_title (title.get_string());
1399         }
1400 }
1401
1402 string 
1403 ProcessorBox::generate_processor_title (boost::shared_ptr<PluginInsert> pi)
1404 {
1405         string maker = pi->plugin()->maker() ? pi->plugin()->maker() : "";
1406         string::size_type email_pos;
1407
1408         if ((email_pos = maker.find_first_of ('<')) != string::npos) {
1409                 maker = maker.substr (0, email_pos - 1);
1410         }
1411
1412         if (maker.length() > 32) {
1413                 maker = maker.substr (0, 32);
1414                 maker += " ...";
1415         }
1416
1417         return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);  
1418 }
1419