fixup auto-connection of new MIDI tracks and MIDI tracks with newly-added audio ports
[ardour2.git] / gtk2_ardour / port_matrix_row_labels.cc
blob94687448376b1b56bcf790cd480bf84cb18821c3
1 /*
2 Copyright (C) 2002-2009 Paul Davis
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.
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.
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.
20 #include <iostream>
21 #include <boost/weak_ptr.hpp>
22 #include <cairo/cairo.h>
23 #include "ardour/bundle.h"
24 #include "port_matrix_row_labels.h"
25 #include "port_matrix.h"
26 #include "port_matrix_body.h"
27 #include "i18n.h"
28 #include "utils.h"
30 using namespace std;
32 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b)
33 : PortMatrixLabels (m, b)
38 void
39 PortMatrixRowLabels::compute_dimensions ()
41 GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
42 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
43 cairo_t* cr = gdk_cairo_create (pm);
45 _longest_port_name = 0;
46 _longest_bundle_name = 0;
48 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
49 we can change between visible groups without the size of the labels jumping around.
52 for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
54 PortGroup::BundleList const r = (*i)->bundles ();
55 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
57 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
59 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
60 continue;
63 cairo_text_extents_t ext;
64 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
65 if (ext.width > _longest_port_name) {
66 _longest_port_name = ext.width;
70 cairo_text_extents_t ext;
71 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
72 if (ext.width > _longest_bundle_name) {
73 _longest_bundle_name = ext.width;
79 if (_matrix->visible_rows()) {
80 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
81 } else {
82 _height = 0;
85 cairo_destroy (cr);
86 g_object_unref (pm);
88 _width = _longest_bundle_name +
89 name_pad() * 2;
91 if (!_matrix->show_only_bundles()) {
92 _width += _longest_port_name;
93 _width += name_pad() * 2;
98 void
99 PortMatrixRowLabels::render (cairo_t* cr)
101 /* BACKGROUND */
103 set_source_rgb (cr, background_colour());
104 cairo_rectangle (cr, 0, 0, _width, _height);
105 cairo_fill (cr);
107 /* BUNDLE AND PORT NAMES */
109 double y = 0;
110 int N = 0;
111 int M = 0;
113 PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
114 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
115 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
117 if (!_matrix->show_only_bundles()) {
118 for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
120 if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
121 continue;
124 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
125 render_channel_name (cr, background_colour (), c, 0, y, ARDOUR::BundleChannel ((*i)->bundle, j));
126 y += grid_spacing();
127 ++M;
129 } else {
130 y += grid_spacing();
133 ++N;
137 void
138 PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t, guint)
140 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
142 if (
143 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
144 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
147 w.channel = -1;
150 if (b == 3) {
152 _matrix->popup_menu (
153 ARDOUR::BundleChannel (),
160 double
161 PortMatrixRowLabels::component_to_parent_x (double x) const
163 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
164 return x + _parent_rectangle.get_x();
167 double
168 PortMatrixRowLabels::parent_to_component_x (double x) const
170 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
171 return x - _parent_rectangle.get_x();
174 double
175 PortMatrixRowLabels::component_to_parent_y (double y) const
177 return y - _body->yoffset() + _parent_rectangle.get_y();
180 double
181 PortMatrixRowLabels::parent_to_component_y (double y) const
183 return y + _body->yoffset() - _parent_rectangle.get_y();
187 double
188 PortMatrixRowLabels::bundle_name_x () const
190 double x = 0;
192 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
193 x = _longest_port_name + name_pad() * 2;
196 return x;
199 double
200 PortMatrixRowLabels::port_name_x () const
202 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
203 return _longest_bundle_name + name_pad() * 2;
204 } else {
205 return 0;
208 return 0;
211 void
212 PortMatrixRowLabels::render_bundle_name (
213 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
216 double const x = bundle_name_x ();
218 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type (b->nchannels());
219 set_source_rgb (cr, bg_colour);
220 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
221 cairo_fill_preserve (cr);
222 set_source_rgb (cr, fg_colour);
223 cairo_set_line_width (cr, label_border_width ());
224 cairo_stroke (cr);
226 cairo_text_extents_t ext;
227 cairo_text_extents (cr, b->name().c_str(), &ext);
228 double const off = (grid_spacing() - ext.height) / 2;
230 set_source_rgb (cr, text_colour());
231 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
232 cairo_show_text (cr, b->name().c_str());
235 void
236 PortMatrixRowLabels::render_channel_name (
237 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
240 set_source_rgb (cr, bg_colour);
241 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
242 cairo_fill_preserve (cr);
243 set_source_rgb (cr, fg_colour);
244 cairo_set_line_width (cr, label_border_width ());
245 cairo_stroke (cr);
247 cairo_text_extents_t ext;
248 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
249 double const off = (grid_spacing() - ext.height) / 2;
251 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
253 /* only plot the name if the bundle has more than one channel;
254 the name of a single channel is assumed to be redundant */
256 set_source_rgb (cr, text_colour());
257 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
258 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
262 double
263 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
265 return 0;
268 double
269 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
271 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
274 void
275 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
277 if (bc.bundle) {
279 if (_matrix->show_only_bundles()) {
280 _body->queue_draw_area (
281 component_to_parent_x (bundle_name_x()) - 1,
282 component_to_parent_y (channel_y (bc)) - 1,
283 _longest_bundle_name + name_pad() * 2 + 2,
284 grid_spacing() + 2
286 } else {
287 _body->queue_draw_area (
288 component_to_parent_x (port_name_x()) - 1,
289 component_to_parent_y (channel_y (bc)) - 1,
290 _longest_port_name + name_pad() * 2 + 2,
291 grid_spacing() + 2
298 void
299 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
301 list<PortMatrixNode> const m = _body->mouseover ();
302 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
304 ARDOUR::BundleChannel c = i->column;
305 ARDOUR::BundleChannel r = i->row;
307 if (c.bundle && r.bundle) {
308 add_channel_highlight (r);
309 } else if (r.bundle) {
310 _body->highlight_associated_channels (_matrix->row_index(), r);
315 void
316 PortMatrixRowLabels::motion (double x, double y)
318 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
320 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
322 bool done = false;
324 if (w.bundle) {
326 if (
327 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
328 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
332 /* if the mouse is over a bundle name, highlight all channels in the bundle */
334 list<PortMatrixNode> n;
336 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
338 if (!_matrix->should_show (w.bundle->channel_type(i))) {
339 continue;
342 ARDOUR::BundleChannel const bc (w.bundle, i);
343 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
346 _body->set_mouseover (n);
347 done = true;
349 } else if (x < _width) {
351 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
352 done = true;
358 if (!done) {
359 /* not over any bundle */
360 _body->set_mouseover (PortMatrixNode ());
361 return;