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.
21 #include "ardour/bundle.h"
22 #include "ardour/types.h"
23 #include "port_matrix_column_labels.h"
24 #include "port_matrix.h"
25 #include "port_matrix_body.h"
32 PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrix* m, PortMatrixBody* b)
33 : PortMatrixLabels (m, b),
40 PortMatrixColumnLabels::compute_dimensions ()
42 GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, gdk_visual_get_depth (gdk_visual_get_system ()));
43 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
44 cairo_t* cr = gdk_cairo_create (pm);
46 /* width of the longest bundle name */
47 _longest_bundle_name = 0;
48 /* width of the longest channel name */
49 _longest_channel_name = 0;
51 /* Compute dimensions using all port groups, so that we allow for the largest and hence
52 we can change between visible groups without the size of the labels jumping around.
55 for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
56 PortGroup::BundleList const c = _matrix->columns()->bundles();
57 for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
59 cairo_text_extents_t ext;
60 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
61 if (ext.width > _longest_bundle_name) {
62 _longest_bundle_name = ext.width;
65 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
67 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
73 (*j)->bundle->channel_name (k).c_str(),
77 if (ext.width > _longest_channel_name) {
78 _longest_channel_name = ext.width;
85 cairo_text_extents_t ext;
86 cairo_text_extents (cr, X_("AQRjpy"), &ext);
87 _text_height = ext.height;
88 _descender_height = ext.height + ext.y_bearing;
90 /* width of the whole thing */
91 if (_matrix->visible_columns()) {
92 _width = group_size (_matrix->visible_columns()) * grid_spacing ();
100 /* height of the whole thing */
102 int a = _longest_bundle_name + 4 * name_pad();
103 if (!_matrix->show_only_bundles()) {
104 a += _longest_channel_name;
107 _height = a * sin (angle()) + _text_height * cos (angle());
108 _overhang = _height / tan (angle ());
113 PortMatrixColumnLabels::basic_text_x_pos (int) const
115 return grid_spacing() / 2 +
116 _text_height / (2 * sin (angle ()));
120 PortMatrixColumnLabels::render (cairo_t* cr)
124 set_source_rgb (cr, background_colour());
125 cairo_rectangle (cr, 0, 0, _width, _height);
128 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
133 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
134 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
136 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
137 render_bundle_name (cr, background_colour (), c, x, 0, (*i)->bundle);
139 if (_matrix->show_only_bundles()) {
142 x += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels()) * grid_spacing();
150 if (!_matrix->show_only_bundles()) {
154 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
156 uint32_t const C = _matrix->count_of_our_type ((*i)->bundle->nchannels ());
158 for (uint32_t j = 0; j < C; ++j) {
159 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
160 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel ((*i)->bundle, j));
165 x += grid_spacing ();
174 PortMatrixColumnLabels::component_to_parent_x (double x) const
176 return x - _body->xoffset() + _parent_rectangle.get_x();
180 PortMatrixColumnLabels::parent_to_component_x (double x) const
182 return x + _body->xoffset() - _parent_rectangle.get_x();
186 PortMatrixColumnLabels::component_to_parent_y (double y) const
188 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
189 return y + _parent_rectangle.get_y();
193 PortMatrixColumnLabels::parent_to_component_y (double y) const
195 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
196 return y - _parent_rectangle.get_y();
200 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
202 list<PortMatrixNode> const m = _body->mouseover ();
203 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
205 ARDOUR::BundleChannel c = i->column;
206 ARDOUR::BundleChannel r = i->row;
208 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
209 add_channel_highlight (c);
210 } else if (c.bundle) {
211 _body->highlight_associated_channels (_matrix->column_index(), c);
216 vector<pair<double, double> >
217 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
219 vector<pair<double, double> > shape;
221 double const lc = _longest_channel_name + name_pad();
222 double const w = grid_spacing();
224 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
226 double x_ = xoff + _height / tan (angle()) + w;
228 shape.push_back (make_pair (x_, y_));
230 shape.push_back (make_pair (x_, y_));
231 x_ -= lc * cos (angle());
232 y_ += lc * sin (angle());
233 shape.push_back (make_pair (x_, y_));
234 x_ += w * pow (sin (angle()), 2);
235 y_ += w * sin (angle()) * cos (angle());
236 shape.push_back (make_pair (x_, y_));
241 double y_ = yoff + _height;
242 shape.push_back (make_pair (x_, y_));
244 shape.push_back (make_pair (x_, y_));
245 x_ += lc * cos (angle());
246 y_ -= lc * sin (angle());
247 shape.push_back (make_pair (x_, y_));
248 x_ -= grid_spacing() * pow (sin (angle()), 2);
249 y_ -= grid_spacing() * sin (angle()) * cos (angle());
250 shape.push_back (make_pair (x_, y_));
257 PortMatrixColumnLabels::render_bundle_name (
258 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
261 set_source_rgb (cr, bg_colour);
264 if (_matrix->show_only_bundles()) {
267 w = _matrix->count_of_our_type_min_1 (b->nchannels()) * grid_spacing();
276 cairo_move_to (cr, x_, y_);
278 cairo_line_to (cr, x_, y_);
279 x_ += _height / tan (angle ());
281 cairo_line_to (cr, x_, y_);
283 cairo_line_to (cr, x_, y_);
284 cairo_line_to (cr, xoff, y);
285 cairo_fill_preserve (cr);
286 set_source_rgb (cr, fg_colour);
287 cairo_set_line_width (cr, label_border_width());
290 set_source_rgb (cr, text_colour());
292 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
294 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
297 if (_matrix->show_only_bundles()) {
300 rl = 3 * name_pad() + _longest_channel_name;
304 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
305 yoff + _height - q * cos (angle ()) - rl * sin (angle())
312 xoff + grid_spacing() - q * sin (angle ()),
313 yoff + _height - q * cos (angle ())
318 cairo_rotate (cr, -angle());
319 cairo_show_text (cr, b->name().c_str());
324 PortMatrixColumnLabels::render_channel_name (
325 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
328 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
330 cairo_move_to (cr, shape[0].first, shape[0].second);
331 for (uint32_t i = 1; i < 4; ++i) {
332 cairo_line_to (cr, shape[i].first, shape[i].second);
334 cairo_line_to (cr, shape[0].first, shape[0].second);
336 set_source_rgb (cr, bg_colour);
337 cairo_fill_preserve (cr);
338 set_source_rgb (cr, fg_colour);
339 cairo_set_line_width (cr, label_border_width());
342 set_source_rgb (cr, text_colour());
344 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
346 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
350 xoff + grid_spacing() - q * sin (angle ()),
351 yoff + _height - q * cos (angle ())
357 double const rl = 3 * name_pad() + _longest_bundle_name;
360 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
361 yoff + _height - q * cos (angle ()) - rl * sin (angle())
365 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
367 /* only plot the name if the bundle has more than one channel;
368 the name of a single channel is assumed to be redundant */
371 cairo_rotate (cr, -angle());
375 bc.bundle->channel_name(bc.channel).c_str()
383 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
385 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
389 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
395 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
401 if (_matrix->show_only_bundles()) {
403 _body->queue_draw_area (
404 component_to_parent_x (channel_x (bc)) - 1,
405 component_to_parent_y (0) - 1,
406 grid_spacing() + _height * tan (angle()) + 2,
412 double const x = channel_x (bc);
413 double const lc = _longest_channel_name + name_pad();
414 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
416 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
418 _body->queue_draw_area (
419 component_to_parent_x (x) - 1,
420 component_to_parent_y (_height - h) - 1,
421 grid_spacing() + lc * cos (angle()) + 2,
425 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
427 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
429 _body->queue_draw_area (
430 component_to_parent_x (x_) - 1,
431 component_to_parent_y (0) - 1,
432 grid_spacing() + lc * cos (angle()) + 2,
441 ARDOUR::BundleChannel
442 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
444 uint32_t const cx = p - (_height - o) * tan (angle ());
445 return PortMatrixComponent::position_to_channel (cx, o, group);
449 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
451 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
454 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
455 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
462 _matrix->popup_menu (
464 ARDOUR::BundleChannel (),
471 PortMatrixColumnLabels::motion (double x, double y)
473 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
476 _body->set_mouseover (PortMatrixNode ());
480 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
483 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
484 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
487 /* if the mouse is over a bundle name, highlight all channels in the bundle */
489 list<PortMatrixNode> n;
491 uint32_t const N = _matrix->count_of_our_type (w.bundle->nchannels ());
493 for (uint32_t i = 0; i < N; ++i) {
494 ARDOUR::BundleChannel const bc (w.bundle, i);
495 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
498 _body->set_mouseover (n);
502 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));