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 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
43 cairo_t* cr = cairo_create (surface);
45 /* width of the longest bundle name */
46 _longest_bundle_name = 0;
47 /* width of the longest channel name */
48 _longest_channel_name = 0;
50 /* Compute dimensions using all port groups, so that we allow for the largest and hence
51 we can change between visible groups without the size of the labels jumping around.
54 for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
55 PortGroup::BundleList const c = _matrix->columns()->bundles();
56 for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
58 cairo_text_extents_t ext;
59 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
60 if (ext.width > _longest_bundle_name) {
61 _longest_bundle_name = ext.width;
64 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
66 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
72 (*j)->bundle->channel_name (k).c_str(),
76 if (ext.width > _longest_channel_name) {
77 _longest_channel_name = ext.width;
84 cairo_text_extents_t ext;
85 cairo_text_extents (cr, X_("AQRjpy"), &ext);
86 _text_height = ext.height;
87 _descender_height = ext.height + ext.y_bearing;
89 /* width of the whole thing */
90 if (_matrix->visible_columns()) {
91 _width = group_size (_matrix->visible_columns()) * grid_spacing ();
97 cairo_surface_destroy (surface);
99 /* height of the whole thing */
101 int a = _longest_bundle_name + 4 * name_pad();
102 if (!_matrix->show_only_bundles()) {
103 a += _longest_channel_name;
106 _height = a * sin (angle()) + _text_height * cos (angle());
107 _overhang = _height / tan (angle ());
112 PortMatrixColumnLabels::basic_text_x_pos (int) const
114 return grid_spacing() / 2 +
115 _text_height / (2 * sin (angle ()));
119 PortMatrixColumnLabels::render (cairo_t* cr)
123 set_source_rgb (cr, background_colour());
124 cairo_rectangle (cr, 0, 0, _width, _height);
127 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
132 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
133 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
135 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
136 render_bundle_name (cr, background_colour (), c, x, 0, (*i)->bundle);
138 if (_matrix->show_only_bundles()) {
141 x += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels()) * grid_spacing();
149 if (!_matrix->show_only_bundles()) {
153 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
155 uint32_t const C = _matrix->count_of_our_type ((*i)->bundle->nchannels ());
157 for (uint32_t j = 0; j < C; ++j) {
158 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
159 ARDOUR::BundleChannel bc (
161 (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
163 render_channel_name (cr, background_colour (), c, x, 0, bc);
168 x += grid_spacing ();
177 PortMatrixColumnLabels::component_to_parent_x (double x) const
179 return x - _body->xoffset() + _parent_rectangle.get_x();
183 PortMatrixColumnLabels::parent_to_component_x (double x) const
185 return x + _body->xoffset() - _parent_rectangle.get_x();
189 PortMatrixColumnLabels::component_to_parent_y (double y) const
191 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
192 return y + _parent_rectangle.get_y();
196 PortMatrixColumnLabels::parent_to_component_y (double y) const
198 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
199 return y - _parent_rectangle.get_y();
203 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
205 list<PortMatrixNode> const m = _body->mouseover ();
206 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
208 ARDOUR::BundleChannel c = i->column;
209 ARDOUR::BundleChannel r = i->row;
211 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
212 add_channel_highlight (c);
213 } else if (c.bundle) {
214 _body->highlight_associated_channels (_matrix->column_index(), c);
219 vector<pair<double, double> >
220 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
222 vector<pair<double, double> > shape;
224 double const lc = _longest_channel_name + name_pad();
225 double const w = grid_spacing();
227 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
229 double x_ = xoff + _height / tan (angle()) + w;
231 shape.push_back (make_pair (x_, y_));
233 shape.push_back (make_pair (x_, y_));
234 x_ -= lc * cos (angle());
235 y_ += lc * sin (angle());
236 shape.push_back (make_pair (x_, y_));
237 x_ += w * pow (sin (angle()), 2);
238 y_ += w * sin (angle()) * cos (angle());
239 shape.push_back (make_pair (x_, y_));
244 double y_ = yoff + _height;
245 shape.push_back (make_pair (x_, y_));
247 shape.push_back (make_pair (x_, y_));
248 x_ += lc * cos (angle());
249 y_ -= lc * sin (angle());
250 shape.push_back (make_pair (x_, y_));
251 x_ -= grid_spacing() * pow (sin (angle()), 2);
252 y_ -= grid_spacing() * sin (angle()) * cos (angle());
253 shape.push_back (make_pair (x_, y_));
260 PortMatrixColumnLabels::render_bundle_name (
261 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
264 set_source_rgb (cr, bg_colour);
267 if (_matrix->show_only_bundles()) {
270 w = _matrix->count_of_our_type_min_1 (b->nchannels()) * grid_spacing();
279 cairo_move_to (cr, x_, y_);
281 cairo_line_to (cr, x_, y_);
282 x_ += _height / tan (angle ());
284 cairo_line_to (cr, x_, y_);
286 cairo_line_to (cr, x_, y_);
287 cairo_line_to (cr, xoff, y);
288 cairo_fill_preserve (cr);
289 set_source_rgb (cr, fg_colour);
290 cairo_set_line_width (cr, label_border_width());
293 set_source_rgb (cr, text_colour());
295 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
297 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
300 if (_matrix->show_only_bundles()) {
303 rl = 3 * name_pad() + _longest_channel_name;
307 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
308 yoff + _height - q * cos (angle ()) - rl * sin (angle())
315 xoff + grid_spacing() - q * sin (angle ()),
316 yoff + _height - q * cos (angle ())
321 cairo_rotate (cr, -angle());
322 cairo_show_text (cr, b->name().c_str());
327 PortMatrixColumnLabels::render_channel_name (
328 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
331 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
333 cairo_move_to (cr, shape[0].first, shape[0].second);
334 for (uint32_t i = 1; i < 4; ++i) {
335 cairo_line_to (cr, shape[i].first, shape[i].second);
337 cairo_line_to (cr, shape[0].first, shape[0].second);
339 set_source_rgb (cr, bg_colour);
340 cairo_fill_preserve (cr);
341 set_source_rgb (cr, fg_colour);
342 cairo_set_line_width (cr, label_border_width());
345 set_source_rgb (cr, text_colour());
347 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
349 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
353 xoff + grid_spacing() - q * sin (angle ()),
354 yoff + _height - q * cos (angle ())
360 double const rl = 3 * name_pad() + _longest_bundle_name;
363 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
364 yoff + _height - q * cos (angle ()) - rl * sin (angle())
368 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
370 /* only plot the name if the bundle has more than one channel;
371 the name of a single channel is assumed to be redundant */
374 cairo_rotate (cr, -angle());
378 bc.bundle->channel_name(bc.channel).c_str()
386 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
388 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
392 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
398 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
404 if (_matrix->show_only_bundles()) {
406 _body->queue_draw_area (
407 component_to_parent_x (channel_x (bc)) - 1,
408 component_to_parent_y (0) - 1,
409 grid_spacing() + _height * tan (angle()) + 2,
415 double const x = channel_x (bc);
416 double const lc = _longest_channel_name + name_pad();
417 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
419 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
421 _body->queue_draw_area (
422 component_to_parent_x (x) - 1,
423 component_to_parent_y (_height - h) - 1,
424 grid_spacing() + lc * cos (angle()) + 2,
428 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
430 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
432 _body->queue_draw_area (
433 component_to_parent_x (x_) - 1,
434 component_to_parent_y (0) - 1,
435 grid_spacing() + lc * cos (angle()) + 2,
444 ARDOUR::BundleChannel
445 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
447 uint32_t const cx = p - (_height - o) * tan (angle ());
448 return PortMatrixComponent::position_to_channel (cx, o, group);
452 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
454 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
457 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
458 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
465 _matrix->popup_menu (
467 ARDOUR::BundleChannel (),
474 PortMatrixColumnLabels::motion (double x, double y)
476 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
479 _body->set_mouseover (PortMatrixNode ());
483 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
486 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
487 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
490 /* if the mouse is over a bundle name, highlight all channels in the bundle */
492 list<PortMatrixNode> n;
494 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
495 if (!_matrix->should_show (w.bundle->channel_type (i))) {
499 ARDOUR::BundleChannel const bc (w.bundle, i);
500 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
503 _body->set_mouseover (n);
507 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));