*fix the bugfix: Input and Output Ports exchanged in Track/Bus inspector
[ardour.git] / gtk2_ardour / io_selector.cc
1 /*
2     Copyright (C) 2002-2007 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 <glibmm/objectbase.h>
21 #include <gtkmm2ext/doi.h>
22 #include <ardour/port_insert.h>
23 #include "ardour/session.h"
24 #include "ardour/io.h"
25 #include "ardour/audioengine.h"
26 #include "ardour/track.h"
27 #include "ardour/audio_track.h"
28 #include "ardour/midi_track.h"
29 #include "ardour/data_type.h"
30 #include "io_selector.h"
31 #include "utils.h"
32 #include "gui_thread.h"
33 #include "i18n.h"
34
35 IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool offer_inputs)
36         : PortMatrix (
37                 session, io->default_type(), !offer_inputs,
38                 PortGroupList::Mask (PortGroupList::BUSS | PortGroupList::SYSTEM | PortGroupList::OTHER)
39                 ),
40           _io (io)
41 {
42         /* Listen for ports changing on the IO */
43         if (_offer_inputs) {
44                 _io->input_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
45         } else {
46                 _io->output_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
47         }
48
49 #ifdef FIXME
50         /* these got lost in a merge from 2.0 */
51         set_button_sensitivity ();
52         io->name_changed.connect (mem_fun(*this, &IOSelector::name_changed));
53 #endif
54
55 }
56
57
58 void
59 IOSelector::ports_changed (ARDOUR::IOChange change, void *src)
60 {
61         ENSURE_GUI_THREAD (bind (mem_fun (*this, &IOSelector::ports_changed), change, src));
62
63         redisplay ();
64 }
65
66
67
68 void
69 IOSelector::set_state (int r, std::string const & p, bool s)
70 {
71         if (s) {
72                 if (!_offer_inputs) {
73                         _io->connect_input (_io->input(r), p, 0);
74                 } else {
75                         _io->connect_output (_io->output(r), p, 0);
76                 }
77         } else {
78                 if (!_offer_inputs) {
79                         _io->disconnect_input (_io->input(r), p, 0);
80                 } else {
81                         _io->disconnect_output (_io->output(r), p, 0);
82                 }
83         }
84 }
85
86 bool
87 IOSelector::get_state (int r, std::string const & p) const
88 {
89         vector<string> connections;
90
91         if (_offer_inputs) {
92                 _io->output(r)->get_connections (connections);
93         } else {
94                 _io->input(r)->get_connections (connections);
95         }
96
97         int k = 0;
98         for (vector<string>::iterator i = connections.begin(); i != connections.end(); ++i) {
99
100                 if ((*i)== p) {
101                         return true;
102                 }
103                 
104                 ++k;
105         }
106
107         return false;
108 }
109
110 uint32_t
111 IOSelector::n_rows () const
112 {
113         if (!_offer_inputs) {
114                 return _io->inputs().num_ports (_io->default_type());
115         } else {
116                 return _io->outputs().num_ports (_io->default_type());
117         }
118 }
119
120 uint32_t
121 IOSelector::maximum_rows () const
122 {
123         if (!_offer_inputs) {
124                 return _io->input_maximum ().get (_io->default_type());
125         } else {
126                 return _io->output_maximum ().get (_io->default_type());
127         }
128 }
129
130
131 uint32_t
132 IOSelector::minimum_rows () const
133 {
134         if (!_offer_inputs) {
135                 return _io->input_minimum ().get (_io->default_type());
136         } else {
137                 return _io->output_minimum ().get (_io->default_type());
138         }
139 }
140
141 std::string
142 IOSelector::row_name (int r) const
143 {
144         if (!_offer_inputs) {
145                 return _io->input(r)->name();
146         } else {
147                 return _io->output(r)->name();
148         }
149                 
150 }
151
152 void
153 IOSelector::add_row ()
154 {
155         // The IO selector only works for single typed IOs
156         const ARDOUR::DataType t = _io->default_type ();
157
158         if (!_offer_inputs) {
159
160                 try {
161                         _io->add_input_port ("", this);
162                 }
163
164                 catch (ARDOUR::AudioEngine::PortRegistrationFailure& err) {
165                         Gtk::MessageDialog msg (0,  _("There are no more JACK ports available."));
166                         msg.run ();
167                 }
168
169         } else {
170
171                 try {
172                         _io->add_output_port ("", this);
173                 }
174
175                 catch (ARDOUR::AudioEngine::PortRegistrationFailure& err) {
176                         Gtk::MessageDialog msg (0, _("There are no more JACK ports available."));
177                         msg.run ();
178                 }
179         }
180 }
181
182
183 void
184 IOSelector::remove_row (int r)
185 {
186         // The IO selector only works for single typed IOs
187         const ARDOUR::DataType t = _io->default_type ();
188         
189         if (!_offer_inputs) {
190                 _io->remove_input_port (_io->input (r), this);
191         } else {
192                 _io->remove_output_port (_io->output (r), this);
193         }
194 }
195
196 std::string
197 IOSelector::row_descriptor () const
198 {
199         return _("port");
200 }
201
202
203
204 IOSelectorWindow::IOSelectorWindow (
205         ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool for_input, bool can_cancel
206         )
207         : ArdourDialog ("I/O selector"),
208           _selector (session, io, !for_input),
209           ok_button (can_cancel ? _("OK"): _("Close")),
210           cancel_button (_("Cancel")),
211           rescan_button (_("Rescan"))
212
213 {
214         add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
215         set_name ("IOSelectorWindow2");
216
217         string title;
218         if (for_input) {
219                 title = string_compose(_("%1 input"), io->name());
220         } else {
221                 title = string_compose(_("%1 output"), io->name());
222         }
223
224         ok_button.set_name ("IOSelectorButton");
225         if (!can_cancel) {
226                 ok_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_BUTTON)));
227         }
228         cancel_button.set_name ("IOSelectorButton");
229         rescan_button.set_name ("IOSelectorButton");
230         rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON)));
231
232         get_action_area()->pack_start (rescan_button, false, false);
233
234         if (can_cancel) {
235                 cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON)));
236                 get_action_area()->pack_start (cancel_button, false, false);
237         } else {
238                 cancel_button.hide();
239         }
240                 
241         get_action_area()->pack_start (ok_button, false, false);
242
243         get_vbox()->set_spacing (8);
244         get_vbox()->pack_start (_selector);
245
246         ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
247         cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
248         rescan_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::rescan));
249
250         set_title (title);
251         set_position (Gtk::WIN_POS_MOUSE);
252
253         show_all ();
254
255         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
256 }
257
258 IOSelectorWindow::~IOSelectorWindow()
259 {
260         
261 }
262
263 void
264 IOSelectorWindow::rescan ()
265 {
266         _selector.redisplay ();
267 }
268
269 void
270 IOSelectorWindow::cancel ()
271 {
272         _selector.Finished (IOSelector::Cancelled);
273         hide ();
274 }
275
276 void
277 IOSelectorWindow::accept ()
278 {
279         _selector.Finished (IOSelector::Accepted);
280         hide ();
281 }
282
283 void
284 IOSelectorWindow::on_map ()
285 {
286         _selector.redisplay ();
287         Window::on_map ();
288 }
289
290
291 PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::PortInsert> pi)
292         : input_selector (sess, pi->io(), true),
293           output_selector (sess, pi->io(), false)
294 {
295         hbox.pack_start (output_selector, true, true);
296         hbox.pack_start (input_selector, true, true);
297
298         pack_start (hbox);
299 }
300
301 void
302 PortInsertUI::redisplay ()
303 {
304         input_selector.redisplay();
305         output_selector.redisplay();
306 }
307
308 void
309 PortInsertUI::finished (IOSelector::Result r)
310 {
311         input_selector.Finished (r);
312         output_selector.Finished (r);
313 }
314
315
316 PortInsertWindow::PortInsertWindow (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::PortInsert> pi, bool can_cancel)
317         : ArdourDialog ("port insert dialog"),
318           _portinsertui (sess, pi),
319           ok_button (can_cancel ? _("OK"): _("Close")),
320           cancel_button (_("Cancel")),
321           rescan_button (_("Rescan"))
322 {
323
324         set_name ("IOSelectorWindow");
325         string title = _("ardour: ");
326         title += pi->name();
327         set_title (title);
328         
329         ok_button.set_name ("IOSelectorButton");
330         if (!can_cancel) {
331                 ok_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_BUTTON)));
332         }
333         cancel_button.set_name ("IOSelectorButton");
334         rescan_button.set_name ("IOSelectorButton");
335         rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON)));
336
337         get_action_area()->pack_start (rescan_button, false, false);
338         if (can_cancel) {
339                 cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON)));
340                 get_action_area()->pack_start (cancel_button, false, false);
341         } else {
342                 cancel_button.hide();
343         }
344         get_action_area()->pack_start (ok_button, false, false);
345
346         get_vbox()->pack_start (_portinsertui);
347
348         ok_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::accept));
349         cancel_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::cancel));
350         rescan_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::rescan));
351
352         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this))); 
353
354         going_away_connection = pi->GoingAway.connect (mem_fun (*this, &PortInsertWindow::plugin_going_away));
355 }
356
357 void
358 PortInsertWindow::plugin_going_away ()
359 {
360         ENSURE_GUI_THREAD (mem_fun (*this, &PortInsertWindow::plugin_going_away));
361         
362         going_away_connection.disconnect ();
363         delete_when_idle (this);
364 }
365
366 void
367 PortInsertWindow::on_map ()
368 {
369         _portinsertui.redisplay ();
370         Window::on_map ();
371 }
372
373
374 void
375 PortInsertWindow::rescan ()
376 {
377         _portinsertui.redisplay ();
378 }
379
380 void
381 PortInsertWindow::cancel ()
382 {
383         _portinsertui.finished (IOSelector::Cancelled);
384         hide ();
385 }
386
387 void
388 PortInsertWindow::accept ()
389 {
390         _portinsertui.finished (IOSelector::Accepted);
391         hide ();
392 }