More logical arrangement of port matrix inputs and outputs, hopefully;
[ardour.git] / gtk2_ardour / port_matrix.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 <iostream>
21 #include <gtkmm/scrolledwindow.h>
22 #include <gtkmm/adjustment.h>
23 #include <gtkmm/label.h>
24 #include "ardour/bundle.h"
25 #include "port_matrix.h"
26 #include "i18n.h"
27
28 /** PortMatrix constructor.
29  *  @param session Our session.
30  *  @param type Port type that we are handling.
31  *  @param offer_inputs true to offer inputs, otherwise false.
32  *  @param mask Mask of port groups to offer.
33  */
34 PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type, bool offer_inputs, PortGroupList::Mask mask)
35         : _offer_inputs (offer_inputs),
36           _port_group_list (session, type, offer_inputs, mask),
37           _type (type),
38           _body (this, offer_inputs ? PortMatrixBody::BOTTOM_AND_LEFT : PortMatrixBody::TOP_AND_RIGHT)
39 {
40         /* checkbuttons for visibility of groups */
41         Gtk::HBox* visibility_buttons = Gtk::manage (new Gtk::HBox);
42
43         visibility_buttons->pack_start (*Gtk::manage (new Gtk::Label (_("Show:"))), Gtk::PACK_SHRINK);
44         
45         for (std::list<PortGroup*>::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
46                 _port_group_uis.push_back (new PortGroupUI (this, *i));
47         }
48
49         for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
50                 visibility_buttons->pack_start ((*i)->visibility_checkbutton(), Gtk::PACK_SHRINK);
51         }
52
53         pack_start (*visibility_buttons, Gtk::PACK_SHRINK);
54         pack_start (_hscroll, Gtk::PACK_SHRINK);
55         Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
56         hbox->pack_start (_body);
57         hbox->pack_start (_vscroll, Gtk::PACK_SHRINK);
58         pack_start (*hbox);
59
60         _hscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::hscroll_changed));
61         _vscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::vscroll_changed));
62         setup_scrollbars ();
63
64         /* XXX hard-coded initial size suggestion */
65         set_size_request (400, 200);
66         show_all ();
67 }
68
69 PortMatrix::~PortMatrix ()
70 {
71         for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
72                 delete *i;
73         }
74 }
75
76 void
77 PortMatrix::setup ()
78 {
79         _port_group_list.refresh ();
80
81         std::vector<boost::shared_ptr<ARDOUR::Bundle> > column;
82         std::vector<boost::shared_ptr<ARDOUR::Bundle> > row;
83
84         for (PortGroupList::iterator i = _port_group_list.begin (); i != _port_group_list.end (); ++i) {
85                 if ((*i)->visible) {
86                         
87                         std::copy ((*i)->bundles.begin(), (*i)->bundles.end(), std::back_inserter (column));
88                         
89                         /* make a bundle for the ports, if there are any */
90                         if (!(*i)->ports.empty()) {
91
92                                 boost::shared_ptr<ARDOUR::Bundle> b (new ARDOUR::Bundle ("", _type, !_offer_inputs));
93                                 
94                                 std::string const pre = common_prefix ((*i)->ports);
95                                 if (!pre.empty()) {
96                                         b->set_name (pre.substr (0, pre.length() - 1));
97                                 }
98
99                                 for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
100                                         std::string const p = (*i)->ports[j];
101                                         b->add_channel (p.substr (pre.length()));
102                                         b->set_port (j, p);
103                                 }
104                                         
105                                 column.push_back (b);
106                         }
107                 }
108         }
109
110         row.push_back (_our_bundle);
111
112         _body.setup (row, column);
113         setup_scrollbars ();
114         queue_draw ();
115 }
116
117 void
118 PortMatrix::set_offer_inputs (bool s)
119 {
120         _offer_inputs = s;
121         _port_group_list.set_offer_inputs (s);
122         setup ();
123 }
124
125 void
126 PortMatrix::set_type (ARDOUR::DataType t)
127 {
128         _type = t;
129         _port_group_list.set_type (t);
130         setup ();
131 }
132
133 void
134 PortMatrix::hscroll_changed ()
135 {
136         _body.set_xoffset (_hscroll.get_adjustment()->get_value());
137 }
138
139 void
140 PortMatrix::vscroll_changed ()
141 {
142         _body.set_yoffset (_vscroll.get_adjustment()->get_value());
143 }
144
145 void
146 PortMatrix::setup_scrollbars ()
147 {
148         Gtk::Adjustment* a = _hscroll.get_adjustment ();
149         a->set_lower (0);
150         a->set_upper (_body.full_scroll_width());
151         a->set_page_size (_body.alloc_scroll_width());
152         a->set_step_increment (32);
153         a->set_page_increment (128);
154
155         a = _vscroll.get_adjustment ();
156         a->set_lower (0);
157         a->set_upper (_body.full_scroll_height());
158         a->set_page_size (_body.alloc_scroll_height());
159         a->set_step_increment (32);
160         a->set_page_increment (128);
161 }
162
163 std::string
164 PortMatrix::common_prefix (std::vector<std::string> const & p) const
165 {
166         /* common prefix before '/' ? */
167         if (p[0].find_first_of ("/") != std::string::npos) {
168                 std::string const fp = p[0].substr (0, (p[0].find_first_of ("/") + 1));
169                 uint32_t j = 1;
170                 while (j < p.size()) {
171                         if (p[j].substr (0, fp.length()) != fp) {
172                                 break;
173                         }
174                         ++j;
175                 }
176                 
177                 if (j == p.size()) {
178                         return fp;
179                 }
180         }
181         
182         /* or before ':' ? */
183         if (p[0].find_first_of (":") != std::string::npos) {
184                 std::string const fp = p[0].substr (0, (p[0].find_first_of (":") + 1));
185                 uint32_t j = 1;
186                 while (j < p.size()) {
187                         if (p[j].substr (0, fp.length()) != fp) {
188                                 break;
189                         }
190                         ++j;
191                 }
192                 
193                 if (j == p.size()) {
194                         return fp;
195                 }
196         }
197
198         return "";
199 }
200
201 void
202 PortMatrix::disassociate_all ()
203 {
204         for (PortGroupList::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
205                 
206                 for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator j = (*i)->bundles.begin(); j != (*i)->bundles.end(); ++j) {
207
208                         for (uint32_t k = 0; k < (*j)->nchannels(); ++k) {
209
210                                 for (uint32_t l = 0; l < _our_bundle->nchannels(); ++l) {
211
212                                         set_state (
213                                                 _our_bundle, l, *j, k, false, 0
214                                                 );
215                                 }
216                         }
217                 }
218         }
219
220         _body.repaint_grid ();
221 }