New matrix-based editor for connections and bundles, based on thorwil's design.
[ardour.git] / gtk2_ardour / port_group.cc
1 /*
2     Copyright (C) 2002-2009 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 "port_group.h"
21 #include "port_matrix.h"
22 #include "i18n.h"
23 #include "ardour/session.h"
24 #include "ardour/audio_track.h"
25 #include "ardour/midi_track.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/bundle.h"
28 #include <boost/shared_ptr.hpp>
29 #include <cstring>
30
31 using namespace std;
32 using namespace Gtk;
33
34 /** Add a bundle to a group.
35  *  @param b Bundle.
36  */
37 void
38 PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
39 {
40         bundles.push_back (b);
41 }
42
43 /** Add a port to a group.
44  *  @param p Port.
45  */
46 void
47 PortGroup::add_port (std::string const &p)
48 {
49         ports.push_back (p);
50 }
51
52 void
53 PortGroup::clear ()
54 {
55         bundles.clear ();
56         ports.clear ();
57 }
58
59 /** PortGroupUI constructor.
60  *  @param m PortMatrix to work for.
61  *  @Param g PortGroup to represent.
62  */
63
64 PortGroupUI::PortGroupUI (PortMatrix* m, PortGroup* g)
65         : _port_matrix (m)
66         , _port_group (g)
67         , _visibility_checkbutton (g->name)
68 {
69         _port_group->visible = true;
70         setup_visibility_checkbutton ();
71         
72         _visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled));
73 }
74
75 /** The visibility of a PortGroupUI has been toggled */
76 void
77 PortGroupUI::visibility_checkbutton_toggled ()
78 {
79         _port_group->visible = _visibility_checkbutton.get_active ();
80         setup_visibility_checkbutton ();
81         _port_matrix->setup ();
82 }
83
84 /** Set up the visibility checkbutton according to PortGroup::visible */
85 void
86 PortGroupUI::setup_visibility_checkbutton ()
87 {
88         if (_visibility_checkbutton.get_active () != _port_group->visible) {
89                 _visibility_checkbutton.set_active (_port_group->visible);
90         }
91 }
92
93 /** PortGroupList constructor.
94  *  @param session Session to get bundles from.
95  *  @param type Type of bundles to offer (audio or MIDI)
96  *  @param offer_inputs true to offer output bundles, otherwise false.
97  *  @param mask Mask of groups to make visible by default.
98  */
99
100 PortGroupList::PortGroupList (ARDOUR::Session & session, ARDOUR::DataType type, bool offer_inputs, Mask mask)
101         : _session (session), _type (type), _offer_inputs (offer_inputs),
102           _buss (_("Bus"), mask & BUSS),
103           _track (_("Track"), mask & TRACK),
104           _system (_("System"), mask & SYSTEM),
105           _other (_("Other"), mask & OTHER)
106 {
107         refresh ();
108 }
109
110 /** Find or re-find all our bundles and set up our lists */
111 void
112 PortGroupList::refresh ()
113 {
114         clear ();
115
116         _buss.clear ();
117         _track.clear ();
118         _system.clear ();
119         _other.clear ();
120
121         /* Find the bundles for routes */
122
123         boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes ();
124
125         for (ARDOUR::Session::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
126
127                 PortGroup* g = 0;
128
129                 if (_type == ARDOUR::DataType::AUDIO) {
130
131                         if (boost::dynamic_pointer_cast<ARDOUR::AudioTrack> (*i)) {
132                                 g = &_track;
133                         } else if (!boost::dynamic_pointer_cast<ARDOUR::MidiTrack>(*i)) {
134                                 g = &_buss;
135                         } 
136
137
138                 } else if (_type == ARDOUR::DataType::MIDI) {
139
140                         if (boost::dynamic_pointer_cast<ARDOUR::MidiTrack> (*i)) {
141                                 g = &_track;
142                         }
143
144                         /* No MIDI busses yet */
145                 } 
146                         
147                 if (g) {
148                         g->add_bundle (_offer_inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs ());
149                 }
150         }
151
152         /* Bundles created by the session */
153         _session.foreach_bundle (sigc::mem_fun (*this, &PortGroupList::maybe_add_session_bundle));
154         
155         /* XXX: inserts, sends, plugin inserts? */
156         
157         /* Now we need to find the non-ardour ports; we do this by first
158            finding all the ports that we can connect to. 
159         */
160
161         const char **ports = _session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ? 
162                                                           JackPortIsInput : JackPortIsOutput);
163         if (ports) {
164
165                 int n = 0;
166                 string client_matching_string;
167
168                 client_matching_string = _session.engine().client_name();
169                 client_matching_string += ':';
170
171                 while (ports[n]) {
172                         std::string const p = ports[n];
173
174                         if (p.substr(0, strlen ("system:")) == "system:") {
175                                 /* system: prefix */
176                                 _system.add_port (p);
177                         } else {
178                                 if (p.substr(0, client_matching_string.length()) != client_matching_string) {
179                                         /* other (non-ardour) prefix */
180                                         _other.add_port (p);
181                                 }
182                         }
183
184                         ++n;
185                 }
186
187                 free (ports);
188         }
189
190         push_back (&_system);
191         push_back (&_buss);
192         push_back (&_track);
193         push_back (&_other);
194 }
195
196 void
197 PortGroupList::set_type (ARDOUR::DataType t)
198 {
199         _type = t;
200 }
201
202 void
203 PortGroupList::set_offer_inputs (bool i)
204 {
205         _offer_inputs = i;
206 }
207
208 void
209 PortGroupList::maybe_add_session_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
210 {
211         if (b->ports_are_inputs () == _offer_inputs) {
212                 _system.bundles.push_back (b);
213         }
214 }