Few cleanups related to signed-ness of minimum/maximum port counts.
[ardour.git] / gtk2_ardour / io_selector.cc
1 /*
2     Copyright (C) 2002-2003 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 <map>
21 #include <vector>
22
23 #include <sigc++/bind.h>
24
25 #include <gtkmm/messagedialog.h>
26
27 #include <glibmm/thread.h>
28
29 #include <ardour/io.h>
30 #include <ardour/route.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/port.h>
33 #include <ardour/port_insert.h>
34 #include <ardour/session.h>
35 #include <ardour/audio_diskstream.h>
36
37 #include <gtkmm2ext/doi.h>
38 #include <gtkmm2ext/gtk_ui.h>
39 #include <gtkmm2ext/utils.h>
40
41 #include "utils.h"
42 #include "io_selector.h"
43 #include "keyboard.h"
44 #include "gui_thread.h"
45
46 #include "i18n.h"
47
48 using namespace std;
49 using namespace Gtk;
50 using namespace Glib;
51 using namespace sigc;
52 using namespace ARDOUR;
53 using namespace PBD;
54 using namespace Gtkmm2ext;
55
56 IOSelectorWindow::IOSelectorWindow (Session& sess, boost::shared_ptr<IO> ior, bool input, bool can_cancel)
57         : ArdourDialog ("i/o selector"),
58           _selector (sess, ior, input),
59           ok_button (can_cancel ? _("OK"): _("Close")),
60           cancel_button (_("Cancel")),
61           rescan_button (_("Rescan"))
62
63 {
64         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
65         set_name ("IOSelectorWindow");
66
67         string title;
68         if (input) {
69                 title = string_compose(_("%1 input"), ior->name());
70         } else {
71                 title = string_compose(_("%1 output"), ior->name());
72         }
73
74         ok_button.set_name ("IOSelectorButton");
75         cancel_button.set_name ("IOSelectorButton");
76         rescan_button.set_name ("IOSelectorButton");
77
78         button_box.set_spacing (5);
79         button_box.set_border_width (5);
80         button_box.set_homogeneous (true);
81         button_box.pack_start (rescan_button);
82
83         if (can_cancel) {
84                 button_box.pack_start (cancel_button);
85         } else {
86                 cancel_button.hide();
87         }
88                 
89         button_box.pack_start (ok_button);
90
91         get_vbox()->pack_start (_selector);
92         get_vbox()->pack_start (button_box, false, false);
93
94         ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
95         cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
96         rescan_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::rescan));
97
98         set_title (title);
99         set_position (WIN_POS_MOUSE);
100
101         ok_button.show();
102         cancel_button.show();
103         rescan_button.show();
104         button_box.show();
105         get_vbox()->show();
106
107         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
108 }
109
110 IOSelectorWindow::~IOSelectorWindow()
111 {
112 }
113
114 void
115 IOSelectorWindow::rescan ()
116 {
117         _selector.redisplay ();
118 }
119
120 void
121 IOSelectorWindow::cancel ()
122 {
123         _selector.Finished(IOSelector::Cancelled);
124         hide ();
125 }
126
127 void
128 IOSelectorWindow::accept ()
129 {
130         _selector.Finished(IOSelector::Accepted);
131         hide ();
132 }
133
134 void
135 IOSelectorWindow::on_map ()
136 {
137         _selector.redisplay ();
138         Window::on_map ();
139 }
140
141 /*************************
142   The IO Selector "widget"
143  *************************/  
144
145 IOSelector::IOSelector (Session& sess, boost::shared_ptr<IO> ior, bool input)
146         : session (sess),
147           io (ior),
148           for_input (input),
149           port_frame (for_input? _("Inputs") : _("Outputs")),
150           add_port_button (for_input? _("Add Input") : _("Add Output")),
151           remove_port_button (for_input? _("Remove Input") : _("Remove Output")),
152           clear_connections_button (_("Disconnect All"))
153 {
154         selected_port = 0;
155
156         notebook.set_name ("IOSelectorNotebook");
157         notebook.set_size_request (-1, 125);
158
159         clear_connections_button.set_name ("IOSelectorButton");
160         add_port_button.set_name ("IOSelectorButton");
161         remove_port_button.set_name ("IOSelectorButton");
162
163         selector_frame.set_name ("IOSelectorFrame");
164         port_frame.set_name ("IOSelectorFrame");
165
166         selector_frame.set_label (_("Available connections"));
167         
168         selector_button_box.set_spacing (5);
169         selector_button_box.set_border_width (5);
170
171         selector_box.set_spacing (5);
172         selector_box.set_border_width (5);
173         selector_box.pack_start (notebook);
174         selector_box.pack_start (selector_button_box, false, false);
175
176         selector_frame.add (selector_box);
177
178         port_box.set_spacing (5);
179         port_box.set_border_width (5);
180
181         port_display_scroller.set_name ("IOSelectorNotebook");
182         port_display_scroller.set_border_width (0);
183         port_display_scroller.set_size_request (-1, 170);
184         port_display_scroller.add (port_box);
185         port_display_scroller.set_policy (POLICY_NEVER,
186                                           POLICY_AUTOMATIC);
187
188         port_button_box.set_spacing (5);
189         port_button_box.set_border_width (5);
190
191         port_button_box.pack_start (add_port_button, false, false);
192
193         // The IO selector only works for single typed IOs
194         const ARDOUR::DataType t = io->default_type();
195
196         if (for_input) {
197                 if (io->input_maximum().get(t) > (uint32_t) io->n_inputs().get(t)) {
198                         add_port_button.set_sensitive (true);
199                 } else {
200                         add_port_button.set_sensitive (false);
201                 }
202
203         } else {
204                 if (io->output_maximum().get(t) > (uint32_t) io->n_outputs().get(t)) {
205                         add_port_button.set_sensitive (true);
206                 } else {
207                         add_port_button.set_sensitive (false);
208                 }
209                         
210         }
211
212         port_button_box.pack_start (remove_port_button, false, false);
213
214         if (for_input) {
215                 if (io->input_minimum().get(t) < (uint32_t) io->n_inputs().get(t)) {
216                         remove_port_button.set_sensitive (true);
217                 } else {
218                         remove_port_button.set_sensitive (false);
219                 }
220                         
221         } else {
222                 if (io->output_minimum().get(t) < (uint32_t) io->n_outputs().get(t)) {
223                         remove_port_button.set_sensitive (true);
224                 } else {
225                         remove_port_button.set_sensitive (false);
226                 }
227         }
228
229         port_button_box.pack_start (clear_connections_button, false, false);
230
231         port_and_button_box.set_border_width (5);
232         port_and_button_box.pack_start (port_button_box, false, false);
233         port_and_button_box.pack_start (port_display_scroller);
234
235         port_frame.add (port_and_button_box);
236
237         port_and_selector_box.set_spacing (5);
238         port_and_selector_box.pack_start (port_frame);
239         port_and_selector_box.pack_start (selector_frame);
240
241         set_spacing (5);
242         set_border_width (5);
243         pack_start (port_and_selector_box);
244
245         rescan();
246         display_ports ();
247
248         clear_connections_button.signal_clicked().connect (mem_fun(*this, &IOSelector::clear_connections));
249
250         add_port_button.signal_clicked().connect (mem_fun(*this, &IOSelector::add_port));
251         remove_port_button.signal_clicked().connect (mem_fun(*this, &IOSelector::remove_port));
252
253         if (for_input) {
254                 io->input_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
255         } else {
256                 io->output_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
257         }
258
259         io->NameChanged.connect (mem_fun(*this, &IOSelector::name_changed));
260
261         main_box.show();
262         port_and_selector_box.show();
263         notebook.show();
264         selector_frame.show();
265         selector_box.show();
266         selector_button_box.show();
267         port_box.show();
268         port_button_box.show();
269         port_and_button_box.show();
270         port_frame.show();
271         add_port_button.show();
272         remove_port_button.show();
273         clear_connections_button.show();
274         port_display_scroller.show();
275
276         show();
277         
278 }
279
280 IOSelector::~IOSelector ()
281 {
282 }
283
284 void 
285 IOSelector::set_button_sensitivity ()
286 {
287         DataType t = io->default_type();
288
289         if (for_input) {
290
291                 if (io->input_maximum().get(t) < 0 || io->input_maximum().get(t) > io->n_inputs().get(t)) {
292                         add_port_button.set_sensitive (true);
293                 } else {
294                         add_port_button.set_sensitive (false);
295                 }
296
297         } else {
298
299                 if (io->output_maximum().get(t) < 0 || io->output_maximum().get(t) > io->n_outputs().get(t)) {
300                         add_port_button.set_sensitive (true);
301                 } else {
302                         add_port_button.set_sensitive (false);
303                 }
304                         
305         }
306
307         if (for_input) {
308                 if (io->n_inputs().get(t) && (io->input_minimum().get(t) < 0 || io->input_minimum().get(t) < io->n_inputs().get(t))) {
309                         remove_port_button.set_sensitive (true);
310                 } else {
311                         remove_port_button.set_sensitive (false);
312                 }
313                         
314         } else {
315                 if (io->n_outputs().get(t) && (io->output_minimum().get(t) < 0 || io->output_minimum().get(t) < io->n_outputs().get(t))) {
316                         remove_port_button.set_sensitive (true);
317                 } else {
318                         remove_port_button.set_sensitive (false);
319                 }
320         }
321 }
322
323
324 void
325 IOSelector::name_changed ()
326 {
327         ENSURE_GUI_THREAD(mem_fun(*this, &IOSelector::name_changed));
328         
329         display_ports ();
330 }
331
332 void
333 IOSelector::clear_connections ()
334 {
335         if (for_input) {
336                 io->disconnect_inputs (this);
337         } else {
338                 io->disconnect_outputs (this);
339         }
340 }
341
342 void
343 IOSelector::rescan ()
344 {
345         using namespace Notebook_Helpers;
346
347         typedef std::map<string,vector<pair<string,string> > > PortMap;
348         PortMap portmap;
349         const char **ports;
350         PageList& pages = notebook.pages();
351         gint current_page;
352         vector<string> rowdata;
353
354         page_selection_connection.disconnect ();
355
356         current_page = notebook.get_current_page ();
357
358         pages.clear ();
359
360         /* get relevant current JACK ports */
361
362         ports = session.engine().get_ports ("", io->default_type().to_jack_type(), for_input ? JackPortIsOutput : JackPortIsInput);
363
364         if (ports == 0) {
365                 return;
366         }
367
368         /* find all the client names and group their ports into a list-by-client */
369         
370         for (int n = 0; ports[n]; ++n) {
371
372                 pair<string,vector<pair<string,string> > > newpair;
373                 pair<string,string> strpair;
374                 pair<PortMap::iterator,bool> result;
375
376                 string str = ports[n];
377                 string::size_type pos;
378                 string portname;
379
380                 pos = str.find (':');
381
382                 newpair.first = str.substr (0, pos);
383                 portname = str.substr (pos+1);
384
385                 result = portmap.insert (newpair);
386
387                 strpair.first = portname;
388                 strpair.second = str;
389
390                 result.first->second.push_back (strpair);
391         }
392
393         PortMap::iterator i;
394
395         for (i = portmap.begin(); i != portmap.end(); ++i) {
396                 
397                 Box *client_box = manage (new VBox);
398                 TreeView *display = manage (new TreeView);
399                 RefPtr<ListStore> model = ListStore::create (port_display_columns);
400                 ScrolledWindow *scroller = manage (new ScrolledWindow);
401
402                 display->set_model (model);
403                 display->append_column (X_("notvisible"), port_display_columns.displayed_name);
404                 display->set_headers_visible (false);
405                 display->get_selection()->set_mode (SELECTION_SINGLE);
406                 display->set_name ("IOSelectorList");
407
408                 for (vector<pair<string,string> >::iterator s = i->second.begin(); s != i->second.end(); ++s) {
409                         
410                         TreeModel::Row row = *(model->append ());
411
412                         row[port_display_columns.displayed_name] = s->first;
413                         row[port_display_columns.full_name] = s->second;
414                 }
415
416                 display->signal_button_release_event().connect (bind (mem_fun(*this, &IOSelector::port_selection_changed), display));
417                 Label *tab_label = manage (new Label);
418
419                 tab_label->set_name ("IOSelectorNotebookTab");
420                 tab_label->set_text ((*i).first);
421
422                 scroller->add (*display);
423                 scroller->set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
424
425                 client_box->pack_start (*scroller);
426
427                 pages.push_back (TabElem (*client_box, *tab_label));
428         }
429
430         notebook.set_current_page (current_page);
431         page_selection_connection = notebook.signal_show().connect (bind (mem_fun (notebook, &Notebook::set_current_page), current_page));
432         selector_box.show_all ();
433 }       
434
435 void
436 IOSelector::display_ports ()
437 {
438         TreeView *firsttview = 0;
439         TreeView *selected_port_tview = 0;
440         {
441                 Glib::Mutex::Lock lm  (port_display_lock);
442                 Port *port;
443                 uint32_t limit;
444                 
445                 // The IO selector only works for single typed IOs
446                 const ARDOUR::DataType t = io->default_type();
447
448                 if (for_input) {
449                         limit = io->n_inputs().get(t);
450                 } else {
451                         limit = io->n_outputs().get(t);
452                 }
453                 
454                 for (slist<TreeView *>::iterator i = port_displays.begin(); i != port_displays.end(); ) {
455                         
456                         slist<TreeView *>::iterator tmp;
457                         
458                         tmp = i;
459                         ++tmp;
460                         
461                         port_box.remove (**i);
462                         delete *i;
463                         port_displays.erase (i);
464                         
465                         i = tmp;
466                 } 
467                 
468                 for (uint32_t n = 0; n < limit; ++n) {
469                         
470                         TreeView* tview;
471                         //ScrolledWindow *scroller;
472                         string really_short_name;
473                         
474                         if (for_input) {
475                                 port = io->input (n);
476                         } else {
477                                 port = io->output (n);
478                         }
479                         
480                         /* we know there is '/' because we put it there */
481                         
482                         really_short_name = port->short_name();
483                         really_short_name = really_short_name.substr (really_short_name.find ('/') + 1);
484
485                         tview = manage (new TreeView());
486                         RefPtr<ListStore> port_model = ListStore::create (port_display_columns);
487                         
488                         if (!firsttview) {
489                                 firsttview = tview;
490                         }
491                         
492                         tview->set_model (port_model);
493                         tview->append_column (really_short_name, port_display_columns.displayed_name);
494                         tview->get_selection()->set_mode (SELECTION_SINGLE);
495                         tview->set_data (X_("port"), port);
496                         tview->set_headers_visible (true);
497                         tview->set_name (X_("IOSelectorPortList"));
498                         
499                         port_box.pack_start (*tview);
500                         port_displays.insert (port_displays.end(), tview);
501                         
502                         /* now fill the clist with the current connections */
503                         
504                         const char **connections = port->get_connections ();
505                         
506                         if (connections) {
507                                 for (uint32_t c = 0; connections[c]; ++c) {
508                                         TreeModel::Row row = *(port_model->append());
509                                         row[port_display_columns.displayed_name] = connections[c];
510                                         row[port_display_columns.full_name] = connections[c];
511                                 }
512                         } 
513                         
514                         if (for_input) {
515                                 
516                                 if (io->input_maximum().get(io->default_type()) == 1) {
517                                         selected_port = port;
518                                         selected_port_tview = tview;
519                                 } else {
520                                         if (port == selected_port) {
521                                                 selected_port_tview = tview;
522                                         }
523                                 }
524                                 
525                         } else {
526                                 
527                                 if (io->output_maximum().get(t) == 1) {
528                                         selected_port = port;
529                                         selected_port_tview = tview;
530                                 } else {
531                                         if (port == selected_port) {
532                                                 selected_port_tview = tview;
533                                         }
534                                 }
535                         }
536                         
537                         TreeViewColumn* col = tview->get_column (0);
538                         
539                         col->set_clickable (true);
540                         
541                         /* handle button events on the column header ... */
542                         col->signal_clicked().connect (bind (mem_fun(*this, &IOSelector::select_treeview), tview));
543
544                         /* ... and within the treeview itself */
545                         tview->signal_button_release_event().connect (bind (mem_fun(*this, &IOSelector::connection_button_release), tview));
546                 }
547                 
548                 port_box.show_all ();
549         }
550         
551         if (!selected_port_tview) {
552                 selected_port_tview = firsttview;
553         }
554
555         if (selected_port_tview) {
556                 select_treeview (selected_port_tview);
557         }
558 }
559
560 bool
561 IOSelector::port_selection_changed (GdkEventButton *ev, TreeView* treeview)
562 {
563         TreeModel::iterator i = treeview->get_selection()->get_selected();
564         int status;
565
566         if (!i) {
567                 return 0;
568         }
569
570         if (selected_port == 0) {
571                 return 0;
572         }
573
574         ustring other_port_name = (*i)[port_display_columns.full_name];
575         
576         if (for_input) {
577                 if ((status = io->connect_input (selected_port, other_port_name, this)) == 0) {
578                         Port *p = session.engine().get_port_by_name (other_port_name);
579                         if (p) {
580                                 p->enable_metering();
581                         }
582                 }
583         } else {
584                 status = io->connect_output (selected_port, other_port_name, this);
585         }
586
587         if (status == 0) {
588                 select_next_treeview ();
589         }
590         
591         treeview->get_selection()->unselect_all();
592         return 0;
593 }
594
595 void
596 IOSelector::ports_changed (IOChange change, void *src)
597 {
598         ENSURE_GUI_THREAD(bind (mem_fun(*this, &IOSelector::ports_changed), change, src));
599         
600         display_ports ();
601 }
602
603 void
604 IOSelector::add_port ()
605 {
606         /* add a new port, then hide the button if we're up to the maximum allowed */
607
608         // The IO selector only works for single typed IOs
609         const ARDOUR::DataType t = io->default_type();
610
611         if (for_input) {
612
613                 try {
614                         io->add_input_port ("", this);
615                 }
616
617                 catch (AudioEngine::PortRegistrationFailure& err) {
618                         MessageDialog msg (0,  _("There are no more JACK ports available."));
619                         msg.run ();
620                 }
621
622         } else {
623
624                 try {
625                         io->add_output_port ("", this);
626                 }
627
628                 catch (AudioEngine::PortRegistrationFailure& err) {
629                         MessageDialog msg (0, _("There are no more JACK ports available."));
630                         msg.run ();
631                 }
632         }
633                 
634         set_button_sensitivity ();
635 }
636
637 void
638 IOSelector::remove_port ()
639 {
640         uint32_t nports;
641
642         // The IO selector only works for single typed IOs
643         const ARDOUR::DataType t = io->default_type();
644         
645         // always remove last port
646         
647         if (for_input) {
648                 if ((nports = io->n_inputs().get(t)) > 0) {
649                         io->remove_input_port (io->input(nports-1), this);
650                 }
651         } else {
652                 if ((nports = io->n_outputs().get(t)) > 0) {
653                         io->remove_output_port (io->output(nports-1), this);
654                 }
655         }
656         
657         set_button_sensitivity ();
658 }
659
660 gint
661 IOSelector::connection_button_release (GdkEventButton *ev, TreeView *treeview)
662 {
663         /* this handles button release on a port name row: i.e. a connection
664            between the named port and the port represented by the treeview.
665         */
666
667         Gtk::TreeModel::iterator iter;
668         TreeModel::Path path;
669         TreeViewColumn* column;
670         int cellx;
671         int celly;
672
673         /* only handle button1 events here */
674
675         if (ev->button != 1) {
676                 return false;
677         }
678         
679         if (!treeview->get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
680                 return false;
681         }
682
683         if ((iter = treeview->get_model()->get_iter (path.to_string()))) {
684
685                 /* path is valid */
686                 ustring connected_port_name = (*iter)[port_display_columns.full_name];
687                 Port *port = reinterpret_cast<Port *> (treeview->get_data (X_("port")));
688                 
689                 if (for_input) {
690                         Port *p = session.engine().get_port_by_name (connected_port_name);
691                         if (p) {
692                                 p->disable_metering();
693                         }
694                         io->disconnect_input (port, connected_port_name, this);
695                 } else {
696                         io->disconnect_output (port, connected_port_name, this);
697                 }
698         }
699
700         return true;
701 }
702
703 void
704 IOSelector::select_next_treeview ()
705 {
706         slist<TreeView*>::iterator next;
707
708         if (port_displays.empty() || port_displays.size() == 1) {
709                 return;
710         }
711
712         for (slist<TreeView *>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
713
714                 if ((*i)->get_name() == "IOSelectorPortListSelected") {
715
716                         ++i;
717
718                         if (i == port_displays.end()) {
719                                 select_treeview (port_displays.front());
720                         } else {
721                                 select_treeview (*i);
722                         }
723                         
724                         break;
725                 }
726         }
727 }
728
729 void
730 IOSelector::select_treeview (TreeView* tview)
731 {
732         /* Gack. TreeView's don't respond visually to a change
733            in their state, so rename them to force a style
734            switch.
735         */
736
737         Glib::Mutex::Lock lm  (port_display_lock);
738         Port* port = reinterpret_cast<Port *> (tview->get_data (X_("port")));
739
740         selected_port = port;
741
742         tview->set_name ("IOSelectorPortListSelected");
743         tview->queue_draw ();
744
745         /* ugly hack to force the column header button to change as well */
746
747         TreeViewColumn* col = tview->get_column (0);
748         GtkTreeViewColumn* ccol = col->gobj();
749         
750         if (ccol->button) {
751                 gtk_widget_set_name (ccol->button, "IOSelectorPortListSelected");       
752                 gtk_widget_queue_draw (ccol->button);
753         }
754
755         for (slist<TreeView*>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
756                 if (*i == tview) {
757                         continue;
758                 }
759                 
760                 col = (*i)->get_column (0);
761                 ccol = col->gobj();
762                 
763                 if (ccol->button) {
764                         gtk_widget_set_name (ccol->button, "IOSelectorPortList");
765                         gtk_widget_queue_draw (ccol->button);
766                 }
767                 
768                 (*i)->set_name ("IOSelectorPortList");
769                 (*i)->queue_draw ();
770         }
771
772         selector_box.show_all ();
773 }
774
775 void
776 IOSelector::redisplay ()
777 {
778         display_ports ();
779
780         if (for_input) {
781                 if (io->input_maximum().get(io->default_type()) != 0) {
782                         rescan ();
783                 }
784         } else {
785                 if (io->output_maximum().get(io->default_type()) != 0) {
786                         rescan();
787                 }
788         }
789 }
790
791 PortInsertUI::PortInsertUI (Session& sess, boost::shared_ptr<PortInsert> pi)
792         : input_selector (sess, pi->io(), true),
793           output_selector (sess, pi->io(), false)
794 {
795         hbox.pack_start (output_selector, true, true);
796         hbox.pack_start (input_selector, true, true);
797
798
799         pack_start (hbox);
800 }
801
802 void
803 PortInsertUI::redisplay()
804 {
805
806         input_selector.redisplay();
807         output_selector.redisplay();
808 }
809
810 void
811 PortInsertUI::finished(IOSelector::Result r)
812 {
813         input_selector.Finished (r);
814         output_selector.Finished (r);
815 }
816
817
818 PortInsertWindow::PortInsertWindow (Session& sess, boost::shared_ptr<PortInsert> pi, bool can_cancel)
819         : ArdourDialog ("port insert dialog"),
820           _portinsertui (sess, pi),
821           ok_button (can_cancel ? _("OK"): _("Close")),
822           cancel_button (_("Cancel")),
823           rescan_button (_("Rescan"))
824 {
825
826         set_name ("IOSelectorWindow");
827         string title = _("ardour: ");
828         title += pi->name();
829         set_title (title);
830         
831         ok_button.set_name ("IOSelectorButton");
832         cancel_button.set_name ("IOSelectorButton");
833         rescan_button.set_name ("IOSelectorButton");
834
835         button_box.set_spacing (5);
836         button_box.set_border_width (5);
837         button_box.set_homogeneous (true);
838         button_box.pack_start (rescan_button);
839         if (can_cancel) {
840                 button_box.pack_start (cancel_button);
841         }
842         else {
843                 cancel_button.hide();
844         }
845         button_box.pack_start (ok_button);
846
847         get_vbox()->pack_start (_portinsertui);
848         get_vbox()->pack_start (button_box, false, false);
849
850         ok_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::accept));
851         cancel_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::cancel));
852         rescan_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::rescan));
853
854         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this))); 
855
856         going_away_connection = pi->GoingAway.connect (mem_fun(*this, &PortInsertWindow::plugin_going_away));
857 }
858
859 void
860 PortInsertWindow::plugin_going_away ()
861 {
862         ENSURE_GUI_THREAD(mem_fun(*this, &PortInsertWindow::plugin_going_away));
863         going_away_connection.disconnect ();
864         delete_when_idle (this);
865 }
866
867 void
868 PortInsertWindow::on_map ()
869 {
870         _portinsertui.redisplay ();
871         Window::on_map ();
872 }
873
874
875 void
876 PortInsertWindow::rescan ()
877 {
878         _portinsertui.redisplay();
879 }
880
881 void
882 PortInsertWindow::cancel ()
883 {
884         _portinsertui.finished(IOSelector::Cancelled);
885         hide ();
886 }
887
888 void
889 PortInsertWindow::accept ()
890 {
891         _portinsertui.finished(IOSelector::Accepted);
892         hide ();
893 }