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