4172d7e9ef6fc8895fa3ae0635a175ea787643ad
[ardour.git] / gtk2_ardour / redirect_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     $Id$
19 */
20
21 #include <cmath>
22 #include <glib.h>
23
24 #include <sigc++/bind.h>
25
26 #include <gtkmm2ext/gtk_ui.h>
27 #include <gtkmm2ext/utils.h>
28 #include <gtkmm2ext/choice.h>
29 #include <gtkmm2ext/utils.h>
30 #include <gtkmm2ext/stop_signal.h>
31 #include <gtkmm2ext/doi.h>
32
33 #include <ardour/ardour.h>
34 #include <ardour/session.h>
35 #include <ardour/audioengine.h>
36 #include <ardour/route.h>
37 #include <ardour/audio_track.h>
38 #include <ardour/diskstream.h>
39 #include <ardour/send.h>
40 #include <ardour/insert.h>
41 #include <ardour/ladspa_plugin.h>
42 #include <ardour/connection.h>
43 #include <ardour/session_connection.h>
44
45 #include "ardour_ui.h"
46 #include "ardour_dialog.h"
47 #include "ardour_message.h"
48 #include "public_editor.h"
49 #include "redirect_box.h"
50 #include "keyboard.h"
51 #include "plugin_selector.h"
52 #include "route_redirect_selection.h"
53 #include "mixer_ui.h"
54 #include "actions.h"
55
56 #include "plugin_ui.h"
57 #include "send_ui.h"
58 #include "io_selector.h"
59 #include "utils.h"
60 #include "gui_thread.h"
61
62 #include "i18n.h"
63
64 using namespace sigc;
65 using namespace ARDOUR;
66 using namespace Gtk;
67 using namespace Glib;
68 using namespace Gtkmm2ext;
69
70 RedirectBox* RedirectBox::_current_redirect_box = 0;
71
72
73 RedirectBox::RedirectBox (Placement pcmnt, Session& sess, Route& rt, PluginSelector &plugsel, 
74                           RouteRedirectSelection & rsel, bool owner_is_mixer)
75         : _route(rt), 
76           _session(sess), 
77           _owner_is_mixer (owner_is_mixer), 
78           _placement(pcmnt), 
79           _plugin_selector(plugsel),
80           _rr_selection(rsel)
81           //redirect_display (1)
82 {
83         _width = Wide;
84         redirect_menu = 0;
85         send_action_menu = 0;
86         redirect_drag_in_progress = false;
87         
88         model = ListStore::create(columns);
89
90         RefPtr<TreeSelection> selection = redirect_display.get_selection();
91         selection->set_mode (Gtk::SELECTION_MULTIPLE);
92         selection->signal_changed().connect (mem_fun (*this, &RedirectBox::selection_changed));
93
94         redirect_display.set_model (model);
95         redirect_display.append_column ("WHY?", columns.text);
96         redirect_display.set_name ("MixerRedirectSelector");
97         redirect_display.set_headers_visible (false);
98         redirect_display.set_reorderable (true);
99         redirect_display.set_size_request (-1, 48);
100         redirect_display.get_column(0)->set_sizing(TREE_VIEW_COLUMN_FIXED);
101         redirect_display.get_column(0)->set_fixed_width(48);
102         redirect_display.add_object_drag (columns.redirect.index(), "redirects");
103         redirect_display.signal_object_drop.connect (mem_fun (*this, &RedirectBox::object_drop));
104
105         // Does this adequately replace the drag start/stop signal handlers?
106         model->signal_rows_reordered().connect (mem_fun (*this, &RedirectBox::redirects_reordered));
107         redirect_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
108
109         redirect_scroller.add (redirect_display);
110         redirect_eventbox.add (redirect_scroller);
111         pack_start (redirect_eventbox, true, true);
112
113         redirect_scroller.show ();
114         redirect_display.show ();
115         redirect_eventbox.show ();
116         show_all ();
117
118         _route.redirects_changed.connect (mem_fun(*this, &RedirectBox::redirects_changed));
119
120         redirect_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (RedirectBox::enter_box), this));
121         //redirect_eventbox.signal_leave_notify_event().connect (bind (sigc::ptr_fun (RedirectBox::leave_box), this));
122
123         redirect_display.signal_button_press_event().connect (mem_fun(*this, &RedirectBox::redirect_button));
124         redirect_display.signal_button_release_event().connect (mem_fun(*this, &RedirectBox::redirect_button));
125
126         //redirect_display.signal_button_release_event().connect_after (ptr_fun (do_not_propagate));
127         set_stuff_from_route ();
128
129         /* start off as a passthru strip. we'll correct this, if necessary,
130            in update_diskstream_display().
131         */
132
133         //set_name ("AudioTrackStripBase");
134
135         /* now force an update of all the various elements */
136
137         redirects_changed (0);
138
139         //add_events (Gdk::BUTTON_RELEASE_MASK);
140 }
141
142 RedirectBox::~RedirectBox ()
143 {
144 //      GoingAway(); /* EMIT_SIGNAL */
145
146 }
147
148 void
149 RedirectBox::object_drop (string type, uint32_t cnt, void** ptr)
150 {
151         if (type != "redirects") {
152                 return;
153         }
154 }
155
156 void
157 RedirectBox::set_stuff_from_route ()
158 {
159 }
160
161 void
162 RedirectBox::set_title (const std::string & title)
163 {
164         redirect_display.get_column(0)->set_title (title);
165 }
166
167 void
168 RedirectBox::set_title_shown (bool flag)
169 {
170 }
171
172
173 void
174 RedirectBox::update()
175 {
176         redirects_changed(0);
177 }
178
179
180 void
181 RedirectBox::set_width (Width w)
182 {
183         if (_width == w) {
184                 return;
185         }
186         _width = w;
187
188         redirects_changed(0);
189 }
190
191
192 void
193 RedirectBox::remove_redirect_gui (Redirect *redirect)
194 {
195         Insert *insert = 0;
196         Send *send = 0;
197         PortInsert *port_insert = 0;
198
199         if ((insert = dynamic_cast<Insert *> (redirect)) != 0) {
200
201                 if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
202                         PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
203                         port_insert->set_gui (0);
204                         delete io_selector;
205                 } 
206
207         } else if ((send = dynamic_cast<Send *> (insert)) != 0) {
208                 SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
209                 send->set_gui (0);
210                 delete sui;
211         }
212 }
213
214 void 
215 RedirectBox::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, &RedirectBox::new_send)));
225         items.push_back (MenuElem (_("Show send controls"), mem_fun(*this, &RedirectBox::show_send_controls)));
226 }
227
228 void
229 RedirectBox::show_send_controls ()
230
231 {
232 }
233
234 void
235 RedirectBox::new_send ()
236
237 {
238 }
239
240 void
241 RedirectBox::show_redirect_menu (gint arg)
242 {
243         if (redirect_menu == 0) {
244                 redirect_menu = build_redirect_menu ();
245         }
246
247         redirect_menu->popup (1, 0);
248 }
249
250 void
251 RedirectBox::redirect_drag_begin (GdkDragContext *context)
252 {
253         redirect_drag_in_progress = true;
254 }
255
256 void
257 RedirectBox::redirect_drag_end (GdkDragContext *context)
258 {
259         redirect_drag_in_progress = false;
260 }
261
262 gint
263 RedirectBox::redirect_button (GdkEventButton *ev)
264 {
265         Redirect *redirect;
266         TreeModel::Row row = *(redirect_display.get_selection()->get_selected());
267
268         if (row)
269                 redirect = row[columns.redirect];
270
271         switch (ev->type) {
272         case GDK_BUTTON_PRESS:
273                 if (ev->button == 3) {
274                         show_redirect_menu (0); // Handle the context-click menu here as well
275                         return TRUE;
276                 }
277                 else
278                         return FALSE;
279
280         case GDK_2BUTTON_PRESS:
281                 if (ev->state != 0) {
282                         return FALSE;
283                 }
284                 /* might be edit event, see below */
285                 break;
286
287         case GDK_BUTTON_RELEASE:
288                 break;
289
290         default:
291                 /* shouldn't be here, but gcc complains */
292                 return FALSE;
293         }
294
295         if (redirect && Keyboard::is_delete_event (ev)) {
296                 
297                 Glib::signal_idle().connect (bind (mem_fun(*this, &RedirectBox::idle_delete_redirect), redirect));
298                 return TRUE;
299
300         } else if (redirect && (Keyboard::is_edit_event (ev) || ev->type == GDK_2BUTTON_PRESS)) {
301                 
302                 if (_session.engine().connected()) {
303                         /* XXX giving an error message here is hard, because we may be in the midst of a button press */
304                         edit_redirect (redirect);
305                 }
306                 return TRUE;
307
308         } else if (Keyboard::is_context_menu_event (ev)) {
309                 show_redirect_menu(0);
310                 return TRUE; //stop_signal (*clist, "button-release-event");
311
312         } else {
313                 switch (ev->button) {
314                 case 1:
315                         return FALSE;
316                         break;
317
318                 case 2:
319                         if (redirect) {
320                                 redirect->set_active (!redirect->active(), this);
321                         }
322                         break;
323
324                 case 3:
325                         break;
326
327                 default:
328                         return FALSE;
329                 }
330         }
331
332         return TRUE;
333 }
334
335 Menu *
336 RedirectBox::build_redirect_menu ()
337 {
338         redirect_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/redirectmenu") );
339         redirect_menu->signal_map_event().connect (mem_fun(*this, &RedirectBox::redirect_menu_map_handler));
340         redirect_menu->set_name ("ArdourContextMenu");
341
342         show_all_children();
343
344         return redirect_menu;
345 }
346
347 void
348 RedirectBox::selection_changed ()
349 {
350         bool sensitive = (redirect_display.get_selection()->count_selected_rows()) ? true : false;
351
352         for (vector<Glib::RefPtr<Gtk::Action> >::iterator i = ActionManager::plugin_selection_sensitive_actions.begin(); i != ActionManager::plugin_selection_sensitive_actions.end(); ++i) {
353                 (*i)->set_sensitive (sensitive);
354         }
355 }
356
357 gint
358 RedirectBox::redirect_menu_map_handler (GdkEventAny *ev)
359 {
360         // GTK2FIX
361         // popup_act_grp->get_action("paste")->set_sensitive (!_rr_selection.redirects.empty());
362         return FALSE;
363 }
364
365 void
366 RedirectBox::select_all_redirects ()
367 {
368         redirect_display.get_selection()->select_all();
369 }
370
371 void
372 RedirectBox::deselect_all_redirects ()
373 {
374         redirect_display.get_selection()->unselect_all();
375 }
376
377 void
378 RedirectBox::choose_plugin ()
379 {
380         sigc::connection newplug_connection = _plugin_selector.PluginCreated.connect (mem_fun(*this,&RedirectBox::insert_plugin_chosen));
381         _plugin_selector.show_all();
382         _plugin_selector.run ();
383         newplug_connection.disconnect();
384 }
385
386 void
387 RedirectBox::insert_plugin_chosen (Plugin *plugin)
388 {
389         if (plugin) {
390
391                 Redirect *redirect = new PluginInsert (_session, *plugin, _placement);
392                 
393                 redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active));
394
395                 uint32_t err_streams;
396
397                 if (_route.add_redirect (redirect, this, &err_streams)) {
398                         wierd_plugin_dialog (*plugin, err_streams, _route);
399                         delete redirect;
400                 }
401         }
402 }
403
404 void
405 RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io)
406 {
407         ArdourDialog dialog ("wierd plugin dialog");
408         Label label;
409
410         /* i hate this kind of code */
411
412         if (streams > p.get_info().n_inputs) {
413                 label.set_text (string_compose (_(
414 "You attempted to add a plugin (%1).\n"
415 "The plugin has %2 inputs\n"
416 "but at the insertion point, there are\n"
417 "%3 active signal streams.\n"
418 "\n"
419 "This makes no sense - you are throwing away\n"
420 "part of the signal."),
421                                          p.name(),
422                                          p.get_info().n_inputs,
423                                          streams));
424         } else if (streams < p.get_info().n_inputs) {
425                 label.set_text (string_compose (_(
426 "You attempted to add a plugin (%1).\n"
427 "The plugin has %2 inputs\n"
428 "but at the insertion point there are\n"
429 "only %3 active signal streams.\n"
430 "\n"
431 "This makes no sense - unless the plugin supports\n"
432 "side-chain inputs. A future version of Ardour will\n"
433 "support this type of configuration."),
434                                          p.name(),
435                                          p.get_info().n_inputs,
436                                          streams));
437         } else {
438                 label.set_text (string_compose (_(
439 "You attempted to add a plugin (%1).\n"
440 "\n"
441 "The I/O configuration doesn't make sense:\n"
442 "\n" 
443 "The plugin has %2 inputs and %3 outputs.\n"
444 "The track/bus has %4 inputs and %5 outputs.\n"
445 "The insertion point, has %6 active signals.\n"
446 "\n"
447 "Ardour does not understand what to do in such situations.\n"),
448                                          p.name(),
449                                          p.get_info().n_inputs,
450                                          p.get_info().n_outputs,
451                                          io.n_inputs(),
452                                          io.n_outputs(),
453                                          streams));
454         }
455
456         dialog.get_vbox()->pack_start (label);
457         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
458
459         dialog.set_name (X_("PluginIODialog"));
460         dialog.set_position (Gtk::WIN_POS_MOUSE);
461         dialog.set_modal (true);
462         dialog.show_all ();
463
464         // GTK2FIX
465         //dialog.realize();
466         //dialog.get_window()->set_decorations (Gdk::WMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
467
468         dialog.run ();
469 }
470
471 void
472 RedirectBox::choose_insert ()
473 {
474         Redirect *redirect = new PortInsert (_session, _placement);
475         redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active));
476         _route.add_redirect (redirect, this);
477 }
478
479 void
480 RedirectBox::choose_send ()
481 {
482         Send *send = new Send (_session, _placement);
483
484         /* XXX need redirect lock on route */
485
486         send->ensure_io (0, _route.max_redirect_outs(), false, this);
487         
488         IOSelectorWindow *ios = new IOSelectorWindow (_session, *send, false, true);
489         
490         ios->show_all ();
491         ios->selector().Finished.connect (bind (mem_fun(*this, &RedirectBox::send_io_finished), static_cast<Redirect*>(send), ios));
492 }
493
494 void
495 RedirectBox::send_io_finished (IOSelector::Result r, Redirect* redirect, IOSelectorWindow* ios)
496 {
497         switch (r) {
498         case IOSelector::Cancelled:
499                 delete redirect;
500                 break;
501
502         case IOSelector::Accepted:
503                 _route.add_redirect (redirect, this);
504                 break;
505         }
506
507         delete_when_idle (ios);
508 }
509
510 void
511 RedirectBox::redirects_changed (void *src)
512 {
513         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::redirects_changed), src));
514         
515         //redirect_display.freeze ();
516         model->clear ();
517         redirect_active_connections.clear ();
518         redirect_name_connections.clear ();
519
520         _route.foreach_redirect (this, &RedirectBox::add_redirect_to_display);
521
522         switch (_placement) {
523         case PreFader:
524                 build_redirect_tooltip(redirect_eventbox, _("Pre-fader inserts, sends & plugins:"));
525                 break;
526         case PostFader:
527                 build_redirect_tooltip(redirect_eventbox, _("Post-fader inserts, sends & plugins:"));
528                 break;
529         }
530         //redirect_display.thaw ();
531 }
532
533 void
534 RedirectBox::add_redirect_to_display (Redirect *redirect)
535 {
536         if (redirect->placement() != _placement) {
537                 return;
538         }
539         
540         Gtk::TreeModel::Row row = *(model->append());
541         row[columns.text] = redirect_name (*redirect);
542         row[columns.redirect] = redirect;
543         
544         show_redirect_active (redirect, this);
545
546         redirect_active_connections.push_back (redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active)));
547         redirect_name_connections.push_back (redirect->name_changed.connect (bind (mem_fun(*this, &RedirectBox::show_redirect_name), redirect)));
548 }
549
550 string
551 RedirectBox::redirect_name (Redirect& redirect)
552 {
553         Send *send;
554         string name_display;
555
556         if (!redirect.active()) {
557                 name_display = " (";
558         }
559
560         if ((send = dynamic_cast<Send *> (&redirect)) != 0) {
561
562                 name_display += '>';
563
564                 /* grab the send name out of its overall name */
565
566                 string::size_type lbracket, rbracket;
567                 lbracket = send->name().find ('[');
568                 rbracket = send->name().find (']');
569
570                 switch (_width) {
571                 case Wide:
572                         name_display += send->name().substr (lbracket+1, lbracket-rbracket-1);
573                         break;
574                 case Narrow:
575                         name_display += short_version (send->name().substr (lbracket+1, lbracket-rbracket-1), 4);
576                         break;
577                 }
578
579         } else {
580
581                 switch (_width) {
582                 case Wide:
583                         name_display += redirect.name();
584                         break;
585                 case Narrow:
586                         name_display += short_version (redirect.name(), 5);
587                         break;
588                 }
589
590         }
591
592         if (!redirect.active()) {
593                 name_display += ')';
594         }
595
596         return name_display;
597 }
598
599 void
600 RedirectBox::build_redirect_tooltip (EventBox& box, string start)
601 {
602         string tip(start);
603
604         Gtk::TreeModel::Children children = model->children();
605         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
606                 Gtk::TreeModel::Row row = *iter;
607                 tip += '\n';
608                 tip += row[columns.text];
609         }
610         ARDOUR_UI::instance()->tooltips().set_tip (box, tip);
611 }
612
613 void
614 RedirectBox::show_redirect_name (void* src, Redirect *redirect)
615 {
616         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_name), src, redirect));
617         
618         show_redirect_active (redirect, src);
619 }
620
621 void
622 RedirectBox::show_redirect_active (Redirect *redirect, void *src)
623 {
624         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_active), redirect, src));
625
626         Gtk::TreeModel::Children children = model->children();
627         Gtk::TreeModel::Children::iterator iter = children.begin();
628
629         while( iter != children.end())
630         {
631                 if ((*iter)[columns.redirect] == redirect)
632                         break;
633                 iter++;
634         }
635
636         (*iter)[columns.text] = redirect_name (*redirect);
637
638         if (redirect->active()) {
639                 redirect_display.get_selection()->select (iter);
640         } else {
641                 redirect_display.get_selection()->unselect (iter);
642         }
643 }
644
645 void
646 RedirectBox::redirects_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter ,int* hmm)
647 {
648         /* this is called before the reorder has been done, so just queue
649            something for idle time.
650         */
651
652         Glib::signal_idle().connect (mem_fun(*this, &RedirectBox::compute_redirect_sort_keys));
653 }
654
655 gint
656 RedirectBox::compute_redirect_sort_keys ()
657 {
658         uint32_t sort_key = 0;
659         Gtk::TreeModel::Children children = model->children();
660
661         for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
662                 Redirect *redirect = (*iter)[columns.redirect];
663                 redirect->set_sort_key (sort_key, this);
664                 sort_key++;
665         }
666
667         if (_route.sort_redirects ()) {
668
669                 redirects_changed (0);
670
671                 /* now tell them about the problem */
672
673                 ArdourDialog dialog ("wierd plugin dialog");
674                 Label label;
675
676                 label.set_text (_("\
677 You cannot reorder this set of redirects\n\
678 in that way because the inputs and\n\
679 outputs do not work correctly."));
680
681                 
682                 dialog.get_vbox()->pack_start (label);
683                 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
684
685                 dialog.set_name (X_("PluginIODialog"));
686                 dialog.set_position (Gtk::WIN_POS_MOUSE);
687                 dialog.set_modal (true);
688                 dialog.show_all ();
689
690                 // GTK2FIX
691                 //dialog.realize();
692                 //dialog.get_window()->set_decorations (Gdk::WMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
693                 
694                 dialog.run ();
695         }
696
697         return FALSE;
698 }
699
700 void
701 RedirectBox::rename_redirects ()
702 {
703         vector<Redirect*> to_be_renamed;
704         
705         get_selected_redirects (to_be_renamed);
706
707         if (to_be_renamed.empty()) {
708                 return;
709         }
710
711         for (vector<Redirect*>::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
712                 rename_redirect (*i);
713         }
714 }
715
716 void
717 RedirectBox::cut_redirects ()
718 {
719         vector<Redirect*> to_be_removed;
720         
721         get_selected_redirects (to_be_removed);
722
723         if (to_be_removed.empty()) {
724                 return;
725         }
726
727         /* this essentially transfers ownership of the redirect
728            of the redirect from the route to the mixer
729            selection.
730         */
731         
732         _rr_selection.set (to_be_removed);
733
734         for (vector<Redirect*>::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
735                 
736                 void* gui = (*i)->get_gui ();
737                 
738                 if (gui) {
739                         static_cast<Gtk::Widget*>(gui)->hide ();
740                 }
741                 
742                 if (_route.remove_redirect (*i, this)) {
743                         /* removal failed */
744                         _rr_selection.remove (*i);
745                 }
746
747         }
748 }
749
750 void
751 RedirectBox::copy_redirects ()
752 {
753         vector<Redirect*> to_be_copied;
754         vector<Redirect*> copies;
755
756         get_selected_redirects (to_be_copied);
757
758         if (to_be_copied.empty()) {
759                 return;
760         }
761
762         for (vector<Redirect*>::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
763                 copies.push_back (Redirect::clone (**i));
764         }
765
766         _rr_selection.set (copies);
767 }
768
769 gint
770 RedirectBox::idle_delete_redirect (Redirect *redirect)
771 {
772         /* NOT copied to _mixer.selection() */
773
774         if (_route.remove_redirect (redirect, this)) {
775                 /* removal failed */
776                 return FALSE;
777         }
778
779         delete redirect;
780         return FALSE;
781 }
782
783 void
784 RedirectBox::rename_redirect (Redirect* redirect)
785 {
786         ArdourDialog dialog (_("ardour: rename redirect"), true);
787         Entry  entry;
788         VBox   vbox;
789         HBox   hbox;
790         Button ok_button (_("OK"));
791         Button cancel_button (_("Cancel"));
792
793         dialog.set_name ("RedirectRenameWindow");
794         dialog.set_size_request (300, -1);
795         dialog.set_position (Gtk::WIN_POS_MOUSE);
796
797         dialog.add_action_widget (entry, RESPONSE_ACCEPT);
798         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
799         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
800         
801         entry.set_name ("RedirectNameDisplay");
802         entry.set_text (redirect->name());
803         entry.select_region (0, -1);
804         entry.grab_focus ();
805
806         switch (dialog.run ()) {
807         case RESPONSE_ACCEPT:
808                 redirect->set_name (entry.get_text(), this);
809                 break;
810         default:
811                 break;
812         }
813 }
814
815 void
816 RedirectBox::cut_redirect (Redirect *redirect)
817 {
818         /* this essentially transfers ownership of the redirect
819            of the redirect from the route to the mixer
820            selection.
821         */
822
823         _rr_selection.add (redirect);
824         
825         void* gui = redirect->get_gui ();
826
827         if (gui) {
828                 static_cast<Gtk::Widget*>(gui)->hide ();
829         }
830         
831         if (_route.remove_redirect (redirect, this)) {
832                 _rr_selection.remove (redirect);
833         }
834 }
835
836 void
837 RedirectBox::copy_redirect (Redirect *redirect)
838 {
839         Redirect* copy = Redirect::clone (*redirect);
840         _rr_selection.add (copy);
841 }
842
843 void
844 RedirectBox::paste_redirects ()
845 {
846         if (_rr_selection.redirects.empty()) {
847                 return;
848         }
849
850         RedirectSelection& sel (_rr_selection.redirects);
851         list<Redirect*> others;
852
853         for (list<Redirect*>::iterator i = sel.begin(); i != sel.end(); ++i) {
854
855                 Redirect* copy = Redirect::clone (**i);
856
857                 copy->set_placement (_placement, this);
858                 others.push_back (copy);
859         }
860
861         if (_route.add_redirects (others, this)) {
862                 for (list<Redirect*>::iterator i = others.begin(); i != others.end(); ++i) {
863                         delete *i;
864                 }
865
866                 string msg = _(
867                         "Copying the set of redirects on the clipboard failed,\n\
868 probably because the I/O configuration of the plugins\n\
869 could not match the configuration of this track.");
870                 ArdourMessage am (0, X_("bad redirect copy dialog"), msg);
871         }
872 }
873
874 void
875 RedirectBox::activate_redirect (Redirect *r)
876 {
877         r->set_active (true, 0);
878 }
879
880 void
881 RedirectBox::deactivate_redirect (Redirect *r)
882 {
883         r->set_active (false, 0);
884 }
885
886 void
887 RedirectBox::get_selected_redirects (vector<Redirect*>& redirects)
888 {
889     vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows();
890  
891         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter)
892                 redirects.push_back ((*(model->get_iter(*iter)))[columns.redirect]);
893 }
894
895 void
896 RedirectBox::for_selected_redirects (void (RedirectBox::*pmf)(Redirect*))
897 {
898     vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows();
899
900         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
901                 Redirect* redirect = (*(model->get_iter(*iter)))[columns.redirect];
902                 (this->*pmf)(redirect);
903         }
904 }
905
906 void
907 RedirectBox::clone_redirects ()
908 {
909         RouteSelection& routes (_rr_selection.routes);
910
911         if (!routes.empty()) {
912                 if (_route.copy_redirects (*routes.front(), _placement)) {
913                         string msg = _(
914 "Copying the set of redirects on the clipboard failed,\n\
915 probably because the I/O configuration of the plugins\n\
916 could not match the configuration of this track.");
917                         ArdourMessage am (0, X_("bad redirect copy dialog"), msg);
918                 }
919         }
920 }
921
922 void
923 RedirectBox::all_redirects_active (bool state)
924 {
925         _route.all_redirects_active (state);
926 }
927
928 void
929 RedirectBox::clear_redirects()
930 {
931         string prompt;
932         vector<string> choices;
933
934         if (dynamic_cast<AudioTrack*>(&_route) != 0) {
935                 prompt = _("Do you really want to remove all redirects from this track?\n"
936                            "(this cannot be undone)");
937         } else {
938                 prompt = _("Do you really want to remove all redirects from this bus?\n"
939                            "(this cannot be undone)");
940         }
941
942         choices.push_back (_("Yes, remove them all"));
943         choices.push_back (_("Cancel"));
944
945         Gtkmm2ext::Choice prompter (prompt, choices);
946
947         prompter.chosen.connect(sigc::ptr_fun(Gtk::Main::quit));
948         prompter.show_all ();
949
950         Gtk::Main::run ();
951
952         if (prompter.get_choice() == 0) {
953                 _route.clear_redirects (this);
954         }
955 }
956
957
958 void
959 RedirectBox::edit_redirect (Redirect* redirect)
960 {
961         Insert *insert;
962
963         if (dynamic_cast<AudioTrack*>(&_route) != 0) {
964
965                 if (dynamic_cast<AudioTrack*> (&_route)->freeze_state() == AudioTrack::Frozen) {
966                         return;
967                 }
968         }
969         
970         if ((insert = dynamic_cast<Insert *> (redirect)) == 0) {
971                 
972                 /* its a send */
973                 
974                 if (!_session.engine().connected()) {
975                         return;
976                 }
977
978                 Send *send = dynamic_cast<Send*> (redirect);
979                 
980                 SendUIWindow *send_ui;
981                 
982                 if (send->get_gui() == 0) {
983                         
984                         string title;
985                         title = string_compose(_("ardour: %1"), send->name());  
986                         
987                         send_ui = new SendUIWindow (*send, _session);
988                         send_ui->set_title (title);
989                         send->set_gui (send_ui);
990                         
991                 } else {
992                         send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
993                 }
994                 
995                 if (send_ui->is_visible()) {
996                         send_ui->get_window()->raise ();
997                 } else {
998                         send_ui->show_all ();
999                 }
1000                 
1001         } else {
1002                 
1003                 /* its an insert */
1004                 
1005                 PluginInsert *plugin_insert;
1006                 PortInsert *port_insert;
1007                 
1008                 if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
1009                         
1010                         PluginUIWindow *plugin_ui;
1011                         
1012                         if (plugin_insert->get_gui() == 0) {
1013                                 
1014                                 string title;
1015                                 string maker = plugin_insert->plugin().maker();
1016                                 string::size_type email_pos;
1017                                 
1018                                 if ((email_pos = maker.find_first_of ('<')) != string::npos) {
1019                                         maker = maker.substr (0, email_pos - 1);
1020                                 }
1021                                 
1022                                 if (maker.length() > 32) {
1023                                         maker = maker.substr (0, 32);
1024                                         maker += " ...";
1025                                 }
1026
1027                                 title = string_compose(_("ardour: %1: %2 (by %3)"), _route.name(), plugin_insert->name(), maker);       
1028                                 
1029                                 plugin_ui = new PluginUIWindow (_session.engine(), *plugin_insert);
1030                                 if (_owner_is_mixer) {
1031                                         ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui);
1032                                 } else {
1033                                         ARDOUR_UI::instance()->the_editor().ensure_float (*plugin_ui);
1034                                 }
1035                                 plugin_ui->set_title (title);
1036                                 plugin_insert->set_gui (plugin_ui);
1037                                 
1038                         } else {
1039                                 plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
1040                         }
1041                         
1042                         if (plugin_ui->is_visible()) {
1043                                 plugin_ui->get_window()->raise ();
1044                         } else {
1045                                 plugin_ui->show_all ();
1046                         }
1047                         
1048                 } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
1049                         
1050                         if (!_session.engine().connected()) {
1051                                 ArdourMessage msg (NULL, "nojackdialog", _("Not connected to JACK - no I/O changes are possible"));
1052                                 return;
1053                         }
1054
1055                         PortInsertWindow *io_selector;
1056
1057                         if (port_insert->get_gui() == 0) {
1058                                 io_selector = new PortInsertWindow (_session, *port_insert);
1059                                 port_insert->set_gui (io_selector);
1060                                 
1061                         } else {
1062                                 io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
1063                         }
1064                         
1065                         if (io_selector->is_visible()) {
1066                                 io_selector->get_window()->raise ();
1067                         } else {
1068                                 io_selector->show_all ();
1069                         }
1070                 }
1071         }
1072 }
1073
1074 bool
1075 RedirectBox::enter_box (GdkEventCrossing *ev, RedirectBox* rb)
1076 {
1077         switch (ev->detail) {
1078         case GDK_NOTIFY_INFERIOR:
1079                 break;
1080
1081         case GDK_NOTIFY_VIRTUAL:
1082                 /* fallthru */
1083
1084         default:
1085                 _current_redirect_box = rb;
1086         }
1087
1088         return false;
1089 }
1090
1091 bool
1092 RedirectBox::leave_box (GdkEventCrossing *ev, RedirectBox* rb)
1093 {
1094         switch (ev->detail) {
1095         case GDK_NOTIFY_INFERIOR:
1096                 break;
1097
1098         case GDK_NOTIFY_VIRTUAL:
1099                 /* fallthru */
1100         default:
1101                 _current_redirect_box = 0;
1102         }
1103
1104         return false;
1105 }
1106
1107 void
1108 RedirectBox::register_actions ()
1109 {
1110         Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("redirectmenu"));
1111         Glib::RefPtr<Action> act;
1112
1113         /* new stuff */
1114         ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin ..."),  sigc::ptr_fun (RedirectBox::rb_choose_plugin));
1115         ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),  sigc::ptr_fun (RedirectBox::rb_choose_insert));
1116         ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),  sigc::ptr_fun (RedirectBox::rb_choose_send));
1117         ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),  sigc::ptr_fun (RedirectBox::rb_clear));
1118
1119         /* standard editing stuff */
1120         act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),  sigc::ptr_fun (RedirectBox::rb_cut));
1121         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1122         act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),  sigc::ptr_fun (RedirectBox::rb_copy));
1123         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1124         ActionManager::ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),  sigc::ptr_fun (RedirectBox::rb_paste));
1125         act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),  sigc::ptr_fun (RedirectBox::rb_rename));
1126         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1127         ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),  sigc::ptr_fun (RedirectBox::rb_select_all));
1128         ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),  sigc::ptr_fun (RedirectBox::rb_deselect_all));
1129                 
1130         /* activation */
1131         act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),  sigc::ptr_fun (RedirectBox::rb_activate));
1132         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1133         act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),  sigc::ptr_fun (RedirectBox::rb_deactivate));
1134         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1135         ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),  sigc::ptr_fun (RedirectBox::rb_activate_all));
1136         ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),  sigc::ptr_fun (RedirectBox::rb_deactivate_all));
1137
1138         /* show editors */
1139         act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),  sigc::ptr_fun (RedirectBox::rb_edit));
1140         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1141
1142         ActionManager::add_action_group (popup_act_grp);
1143 }
1144
1145 void
1146 RedirectBox::rb_choose_plugin ()
1147 {
1148         if (_current_redirect_box == 0) {
1149                 return;
1150         }
1151         _current_redirect_box->choose_plugin ();
1152 }
1153
1154 void
1155 RedirectBox::rb_choose_insert ()
1156 {
1157         if (_current_redirect_box == 0) {
1158                 return;
1159         }
1160         _current_redirect_box->choose_insert ();
1161 }
1162
1163 void
1164 RedirectBox::rb_choose_send ()
1165 {
1166         if (_current_redirect_box == 0) {
1167                 return;
1168         }
1169         _current_redirect_box->choose_send ();
1170 }
1171
1172 void
1173 RedirectBox::rb_clear ()
1174 {
1175         if (_current_redirect_box == 0) {
1176                 return;
1177         }
1178
1179         _current_redirect_box->clear_redirects ();
1180 }
1181
1182 void
1183 RedirectBox::rb_cut ()
1184 {
1185         if (_current_redirect_box == 0) {
1186                 return;
1187         }
1188
1189         _current_redirect_box->cut_redirects ();
1190 }
1191
1192 void
1193 RedirectBox::rb_copy ()
1194 {
1195         if (_current_redirect_box == 0) {
1196                 return;
1197         }
1198         _current_redirect_box->copy_redirects ();
1199 }
1200
1201 void
1202 RedirectBox::rb_paste ()
1203 {
1204         if (_current_redirect_box == 0) {
1205                 return;
1206         }
1207 }
1208
1209 void
1210 RedirectBox::rb_rename ()
1211 {
1212         if (_current_redirect_box == 0) {
1213                 return;
1214         }
1215         _current_redirect_box->rename_redirects ();
1216 }
1217
1218 void
1219 RedirectBox::rb_select_all ()
1220 {
1221         if (_current_redirect_box == 0) {
1222                 return;
1223         }
1224
1225         _current_redirect_box->select_all_redirects ();
1226 }
1227
1228 void
1229 RedirectBox::rb_deselect_all ()
1230 {
1231         if (_current_redirect_box == 0) {
1232                 return;
1233         }
1234
1235         _current_redirect_box->deselect_all_redirects ();
1236 }
1237
1238 void
1239 RedirectBox::rb_activate ()
1240 {
1241         if (_current_redirect_box == 0) {
1242                 return;
1243         }
1244
1245         _current_redirect_box->for_selected_redirects (&RedirectBox::activate_redirect);
1246 }
1247
1248 void
1249 RedirectBox::rb_deactivate ()
1250 {
1251         if (_current_redirect_box == 0) {
1252                 return;
1253         }
1254         _current_redirect_box->for_selected_redirects (&RedirectBox::deactivate_redirect);
1255 }
1256
1257 void
1258 RedirectBox::rb_activate_all ()
1259 {
1260         if (_current_redirect_box == 0) {
1261                 return;
1262         }
1263
1264         _current_redirect_box->all_redirects_active (true);
1265 }
1266
1267 void
1268 RedirectBox::rb_deactivate_all ()
1269 {
1270         if (_current_redirect_box == 0) {
1271                 return;
1272         }
1273         _current_redirect_box->all_redirects_active (false);
1274 }
1275
1276 void
1277 RedirectBox::rb_edit ()
1278 {
1279         if (_current_redirect_box == 0) {
1280                 return;
1281         }
1282
1283         _current_redirect_box->for_selected_redirects (&RedirectBox::edit_redirect);
1284 }
1285