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