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