enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / gtk2_ardour / monitor_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 <stdint.h>
21
22 #include <glibmm/objectbase.h>
23
24 #include <gtkmm2ext/doi.h>
25
26 #include "ardour/audioengine.h"
27 #include "ardour/bundle.h"
28 #include "ardour/data_type.h"
29 #include "ardour/io.h"
30 #include "ardour/port.h"
31 #include "ardour/session.h"
32
33 #include "monitor_selector.h"
34 #include "utils.h"
35 #include "gui_thread.h"
36 #include "pbd/i18n.h"
37
38 using namespace ARDOUR;
39 using namespace ARDOUR_UI_UTILS;
40 using namespace Gtk;
41
42 MonitorSelector::MonitorSelector (Gtk::Window* p, ARDOUR::Session* session, boost::shared_ptr<ARDOUR::IO> io)
43         : PortMatrix (p, session, DataType::AUDIO)
44         , _io (io)
45 {
46         set_type (DataType::AUDIO);
47
48         /* signal flow from 0 to 1 */
49
50         _find_inputs_for_io_outputs = (_io->direction() == IO::Output);
51
52         if (_find_inputs_for_io_outputs) {
53                 _other = 1;
54                 _ours = 0;
55         } else {
56                 _other = 0;
57                 _ours = 1;
58         }
59
60         _port_group.reset (new PortGroup (io->name()));
61         _ports[_ours].add_group (_port_group);
62
63         io->changed.connect (_io_connection, invalidator (*this), boost::bind (&MonitorSelector::io_changed_proxy, this), gui_context ());
64
65         setup_all_ports ();
66         init ();
67 }
68
69 void
70 MonitorSelector::io_changed_proxy ()
71 {
72         /* The IO's changed signal is emitted from code that holds its route's processor lock,
73            so we can't call setup_all_ports (which results in a call to Route::foreach_processor)
74            without a deadlock unless we break things up with this idle handler.
75         */
76
77         Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MonitorSelector::io_changed));
78 }
79
80 void
81 MonitorSelector::io_changed ()
82 {
83         setup_all_ports ();
84 }
85
86 void
87 MonitorSelector::setup_ports (int dim)
88 {
89         if (!_session) {
90                 return;
91         }
92
93         _ports[dim].suspend_signals ();
94
95         if (dim == _other) {
96
97                 _ports[_other].gather (_session, type(), _find_inputs_for_io_outputs, false, show_only_bundles ());
98
99         } else {
100
101                 _port_group->clear ();
102                 _port_group->add_bundle (_io->bundle (), _io);
103         }
104
105         _ports[dim].resume_signals ();
106 }
107
108 void
109 MonitorSelector::set_state (ARDOUR::BundleChannel c[2], bool s)
110 {
111         ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel);
112         ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel);
113
114         for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
115                 for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
116
117                         boost::shared_ptr<Port> f = _session->engine().get_port_by_name (*i);
118                         if (!f) {
119                                 return;
120                         }
121
122                         if (s) {
123                                 if (!f->connected_to (*j)) {
124                                         _io->connect (f, *j, 0);
125                                 }
126                         } else {
127                                 if (f->connected_to (*j)) {
128                                         _io->disconnect (f, *j, 0);
129                                 }
130                         }
131                 }
132         }
133 }
134
135 PortMatrixNode::State
136 MonitorSelector::get_state (ARDOUR::BundleChannel c[2]) const
137 {
138         if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
139                 return PortMatrixNode::NOT_ASSOCIATED;
140         }
141
142         ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel);
143         ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel);
144
145         if (!_session || our_ports.empty() || other_ports.empty()) {
146                 /* we're looking at a bundle with no parts associated with this channel,
147                    so nothing to connect */
148                 return PortMatrixNode::NOT_ASSOCIATED;
149         }
150
151         for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
152                 for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
153
154                         boost::shared_ptr<Port> f = _session->engine().get_port_by_name (*i);
155
156                         /* since we are talking about an IO, our ports should all have an associated Port *,
157                            so the above call should never fail */
158                         assert (f);
159
160                         if (!f->connected_to (*j)) {
161                                 /* if any one thing is not connected, all bets are off */
162                                 return PortMatrixNode::NOT_ASSOCIATED;
163                         }
164                 }
165         }
166
167         return PortMatrixNode::ASSOCIATED;
168 }
169
170 uint32_t
171 MonitorSelector::n_io_ports () const
172 {
173         if (!_find_inputs_for_io_outputs) {
174                 return _io->n_ports().get (_io->default_type());
175         } else {
176                 return _io->n_ports().get (_io->default_type());
177         }
178 }
179
180 bool
181 MonitorSelector::list_is_global (int dim) const
182 {
183         return (dim == _other);
184 }
185
186 std::string
187 MonitorSelector::disassociation_verb () const
188 {
189         return _("Disconnect");
190 }
191
192 std::string
193 MonitorSelector::channel_noun () const
194 {
195         return _("port");
196 }
197
198 MonitorSelectorWindow::MonitorSelectorWindow (ARDOUR::Session* session, boost::shared_ptr<ARDOUR::IO> io, bool /*can_cancel*/)
199         : ArdourWindow (_("Monitor output selector"))
200         , _selector (this, session, io)
201 {
202         set_name ("IOSelectorWindow2");
203
204         add (_selector);
205
206         io_name_changed (this);
207
208         show_all ();
209
210         signal_delete_event().connect (sigc::mem_fun (*this, &MonitorSelectorWindow::wm_delete));
211 }
212
213 bool
214 MonitorSelectorWindow::wm_delete (GdkEventAny* /*event*/)
215 {
216         _selector.Finished (MonitorSelector::Accepted);
217         return false;
218 }
219
220
221 void
222 MonitorSelectorWindow::on_map ()
223 {
224         _selector.setup_all_ports ();
225         Window::on_map ();
226 }
227
228 void
229 MonitorSelectorWindow::on_show ()
230 {
231         Gtk::Window::on_show ();
232         std::pair<uint32_t, uint32_t> const pm_max = _selector.max_size ();
233         resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
234 }
235
236 void
237 MonitorSelectorWindow::io_name_changed (void*)
238 {
239         ENSURE_GUI_THREAD (*this, &MonitorSelectorWindow::io_name_changed, src)
240
241         std::string title;
242
243         if (!_selector.find_inputs_for_io_outputs()) {
244                 title = string_compose(_("%1 input"), _selector.io()->name());
245         } else {
246                 title = string_compose(_("%1 output"), _selector.io()->name());
247         }
248
249         set_title (title);
250 }
251