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, 24);
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 ((*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 for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
158 if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
162 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
163 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel ((*i)->bundle, j));
173 PortMatrixColumnLabels::component_to_parent_x (double x) const
175 return x - _body->xoffset() + _parent_rectangle.get_x();
179 PortMatrixColumnLabels::parent_to_component_x (double x) const
181 return x + _body->xoffset() - _parent_rectangle.get_x();
185 PortMatrixColumnLabels::component_to_parent_y (double y) const
187 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
188 return y + _parent_rectangle.get_y();
192 PortMatrixColumnLabels::parent_to_component_y (double y) const
194 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
195 return y - _parent_rectangle.get_y();
199 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
201 list<PortMatrixNode> const m = _body->mouseover ();
202 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
204 ARDOUR::BundleChannel c = i->column;
205 ARDOUR::BundleChannel r = i->row;
207 if (c.bundle && r.bundle) {
208 add_channel_highlight (c);
209 } else if (c.bundle) {
210 _body->highlight_associated_channels (_matrix->column_index(), c);
215 vector<pair<double, double> >
216 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
218 vector<pair<double, double> > shape;
220 double const lc = _longest_channel_name + name_pad();
221 double const w = grid_spacing();
223 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
225 double x_ = xoff + _height / tan (angle()) + w;
227 shape.push_back (make_pair (x_, y_));
229 shape.push_back (make_pair (x_, y_));
230 x_ -= lc * cos (angle());
231 y_ += lc * sin (angle());
232 shape.push_back (make_pair (x_, y_));
233 x_ += w * pow (sin (angle()), 2);
234 y_ += w * sin (angle()) * cos (angle());
235 shape.push_back (make_pair (x_, y_));
240 double y_ = yoff + _height;
241 shape.push_back (make_pair (x_, y_));
243 shape.push_back (make_pair (x_, y_));
244 x_ += lc * cos (angle());
245 y_ -= lc * sin (angle());
246 shape.push_back (make_pair (x_, y_));
247 x_ -= grid_spacing() * pow (sin (angle()), 2);
248 y_ -= grid_spacing() * sin (angle()) * cos (angle());
249 shape.push_back (make_pair (x_, y_));
256 PortMatrixColumnLabels::render_bundle_name (
257 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
260 set_source_rgb (cr, bg_colour);
263 if (_matrix->show_only_bundles()) {
266 w = _matrix->count_of_our_type (b->nchannels()) * grid_spacing();
275 cairo_move_to (cr, x_, y_);
277 cairo_line_to (cr, x_, y_);
278 x_ += _height / tan (angle ());
280 cairo_line_to (cr, x_, y_);
282 cairo_line_to (cr, x_, y_);
283 cairo_line_to (cr, xoff, y);
284 cairo_fill_preserve (cr);
285 set_source_rgb (cr, fg_colour);
286 cairo_set_line_width (cr, label_border_width());
289 set_source_rgb (cr, text_colour());
291 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
293 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
296 if (_matrix->show_only_bundles()) {
299 rl = 3 * name_pad() + _longest_channel_name;
303 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
304 yoff + _height - q * cos (angle ()) - rl * sin (angle())
311 xoff + grid_spacing() - q * sin (angle ()),
312 yoff + _height - q * cos (angle ())
317 cairo_rotate (cr, -angle());
318 cairo_show_text (cr, b->name().c_str());
323 PortMatrixColumnLabels::render_channel_name (
324 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
327 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
329 cairo_move_to (cr, shape[0].first, shape[0].second);
330 for (uint32_t i = 1; i < 4; ++i) {
331 cairo_line_to (cr, shape[i].first, shape[i].second);
333 cairo_line_to (cr, shape[0].first, shape[0].second);
335 set_source_rgb (cr, bg_colour);
336 cairo_fill_preserve (cr);
337 set_source_rgb (cr, fg_colour);
338 cairo_set_line_width (cr, label_border_width());
341 set_source_rgb (cr, text_colour());
343 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
345 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
349 xoff + grid_spacing() - q * sin (angle ()),
350 yoff + _height - q * cos (angle ())
356 double const rl = 3 * name_pad() + _longest_bundle_name;
359 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
360 yoff + _height - q * cos (angle ()) - rl * sin (angle())
364 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
366 /* only plot the name if the bundle has more than one channel;
367 the name of a single channel is assumed to be redundant */
370 cairo_rotate (cr, -angle());
374 bc.bundle->channel_name(bc.channel).c_str()
382 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
384 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
388 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
394 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
400 if (_matrix->show_only_bundles()) {
402 _body->queue_draw_area (
403 component_to_parent_x (channel_x (bc)) - 1,
404 component_to_parent_y (0) - 1,
405 grid_spacing() + _height * tan (angle()) + 2,
411 double const x = channel_x (bc);
412 double const lc = _longest_channel_name + name_pad();
413 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
415 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
417 _body->queue_draw_area (
418 component_to_parent_x (x) - 1,
419 component_to_parent_y (_height - h) - 1,
420 grid_spacing() + lc * cos (angle()) + 2,
424 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
426 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
428 _body->queue_draw_area (
429 component_to_parent_x (x_) - 1,
430 component_to_parent_y (0) - 1,
431 grid_spacing() + lc * cos (angle()) + 2,
440 ARDOUR::BundleChannel
441 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
443 uint32_t const cx = p - (_height - o) * tan (angle ());
444 return PortMatrixComponent::position_to_channel (cx, o, group);
448 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
450 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
453 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
454 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
461 _matrix->popup_menu (
463 ARDOUR::BundleChannel (),
470 PortMatrixColumnLabels::motion (double x, double y)
472 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
475 _body->set_mouseover (PortMatrixNode ());
479 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
482 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
483 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
486 /* if the mouse is over a bundle name, highlight all channels in the bundle */
488 list<PortMatrixNode> n;
490 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
492 if (!_matrix->should_show (w.bundle->channel_type(i))) {
496 ARDOUR::BundleChannel const bc (w.bundle, i);
497 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
500 _body->set_mouseover (n);
504 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));