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"
30 PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrix* m, PortMatrixBody* b)
31 : PortMatrixLabels (m, b),
38 PortMatrixColumnLabels::compute_dimensions ()
40 GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
41 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
42 cairo_t* cr = gdk_cairo_create (pm);
44 /* width of the longest bundle name */
45 _longest_bundle_name = 0;
46 /* width of the longest channel name */
47 _longest_channel_name = 0;
49 /* Compute dimensions using all port groups, so that we allow for the largest and hence
50 we can change between visible groups without the size of the labels jumping around.
53 for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
54 PortGroup::BundleList const c = _matrix->columns()->bundles();
55 for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
57 cairo_text_extents_t ext;
58 cairo_text_extents (cr, j->bundle->name().c_str(), &ext);
59 if (ext.width > _longest_bundle_name) {
60 _longest_bundle_name = ext.width;
63 for (uint32_t k = 0; k < j->bundle->nchannels (); ++k) {
67 j->bundle->channel_name (k).c_str(),
71 if (ext.width > _longest_channel_name) {
72 _longest_channel_name = ext.width;
79 cairo_text_extents_t ext;
80 cairo_text_extents (cr, X_("AQRjpy"), &ext);
81 _text_height = ext.height;
82 _descender_height = ext.height + ext.y_bearing;
84 /* width of the whole thing */
85 if (_matrix->visible_columns()) {
86 _width = group_size (_matrix->visible_columns()) * grid_spacing ();
92 gdk_pixmap_unref (pm);
94 /* height of the whole thing */
96 int a = _longest_bundle_name + 4 * name_pad();
97 if (!_matrix->show_only_bundles()) {
98 a += _longest_channel_name;
101 _height = a * sin (angle()) + _text_height * cos (angle());
102 _overhang = _height / tan (angle ());
107 PortMatrixColumnLabels::basic_text_x_pos (int) const
109 return grid_spacing() / 2 +
110 _text_height / (2 * sin (angle ()));
114 PortMatrixColumnLabels::render (cairo_t* cr)
118 set_source_rgb (cr, background_colour());
119 cairo_rectangle (cr, 0, 0, _width, _height);
122 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
127 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
128 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
130 Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N);
131 render_bundle_name (cr, background_colour (), c, x, 0, i->bundle);
133 if (_matrix->show_only_bundles()) {
136 x += i->bundle->nchannels () * grid_spacing();
144 if (!_matrix->show_only_bundles()) {
148 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
150 for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) {
151 Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N);
152 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel (i->bundle, j));
162 PortMatrixColumnLabels::component_to_parent_x (double x) const
164 return x - _body->xoffset() + _parent_rectangle.get_x();
168 PortMatrixColumnLabels::parent_to_component_x (double x) const
170 return x + _body->xoffset() - _parent_rectangle.get_x();
174 PortMatrixColumnLabels::component_to_parent_y (double y) const
176 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
177 return y + _parent_rectangle.get_y();
181 PortMatrixColumnLabels::parent_to_component_y (double y) const
183 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
184 return y - _parent_rectangle.get_y();
188 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
190 list<PortMatrixNode> const m = _body->mouseover ();
191 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
193 ARDOUR::BundleChannel c = i->column;
194 ARDOUR::BundleChannel r = i->row;
196 if (c.bundle && r.bundle) {
197 add_channel_highlight (c);
198 } else if (c.bundle) {
199 _body->highlight_associated_channels (_matrix->column_index(), c);
204 vector<pair<double, double> >
205 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
207 vector<pair<double, double> > shape;
209 double const lc = _longest_channel_name + name_pad();
210 double const w = grid_spacing();
212 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
214 double x_ = xoff + _height / tan (angle()) + w;
216 shape.push_back (make_pair (x_, y_));
218 shape.push_back (make_pair (x_, y_));
219 x_ -= lc * cos (angle());
220 y_ += lc * sin (angle());
221 shape.push_back (make_pair (x_, y_));
222 x_ += w * pow (sin (angle()), 2);
223 y_ += w * sin (angle()) * cos (angle());
224 shape.push_back (make_pair (x_, y_));
229 double y_ = yoff + _height;
230 shape.push_back (make_pair (x_, y_));
232 shape.push_back (make_pair (x_, y_));
233 x_ += lc * cos (angle());
234 y_ -= lc * sin (angle());
235 shape.push_back (make_pair (x_, y_));
236 x_ -= grid_spacing() * pow (sin (angle()), 2);
237 y_ -= grid_spacing() * sin (angle()) * cos (angle());
238 shape.push_back (make_pair (x_, y_));
245 PortMatrixColumnLabels::render_bundle_name (
246 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
249 set_source_rgb (cr, bg_colour);
252 if (_matrix->show_only_bundles()) {
255 w = b->nchannels() * grid_spacing();
264 cairo_move_to (cr, x_, y_);
266 cairo_line_to (cr, x_, y_);
267 x_ += _height / tan (angle ());
269 cairo_line_to (cr, x_, y_);
271 cairo_line_to (cr, x_, y_);
272 cairo_line_to (cr, xoff, y);
273 cairo_fill_preserve (cr);
274 set_source_rgb (cr, fg_colour);
275 cairo_set_line_width (cr, label_border_width());
278 set_source_rgb (cr, text_colour());
280 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
282 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
285 if (_matrix->show_only_bundles()) {
288 rl = 3 * name_pad() + _longest_channel_name;
292 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
293 yoff + _height - q * cos (angle ()) - rl * sin (angle())
300 xoff + grid_spacing() - q * sin (angle ()),
301 yoff + _height - q * cos (angle ())
306 cairo_rotate (cr, -angle());
307 cairo_show_text (cr, b->name().c_str());
312 PortMatrixColumnLabels::render_channel_name (
313 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
316 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
318 cairo_move_to (cr, shape[0].first, shape[0].second);
319 for (uint32_t i = 1; i < 4; ++i) {
320 cairo_line_to (cr, shape[i].first, shape[i].second);
322 cairo_line_to (cr, shape[0].first, shape[0].second);
324 set_source_rgb (cr, bg_colour);
325 cairo_fill_preserve (cr);
326 set_source_rgb (cr, fg_colour);
327 cairo_set_line_width (cr, label_border_width());
330 set_source_rgb (cr, text_colour());
332 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
334 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
338 xoff + grid_spacing() - q * sin (angle ()),
339 yoff + _height - q * cos (angle ())
345 double const rl = 3 * name_pad() + _longest_bundle_name;
348 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
349 yoff + _height - q * cos (angle ()) - rl * sin (angle())
353 if (bc.bundle->nchannels() > 1) {
355 /* only plot the name if the bundle has more than one channel;
356 the name of a single channel is assumed to be redundant */
359 cairo_rotate (cr, -angle());
363 bc.bundle->channel_name(bc.channel).c_str()
371 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
373 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
377 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
383 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
389 if (_matrix->show_only_bundles()) {
391 _body->queue_draw_area (
392 component_to_parent_x (channel_x (bc)) - 1,
393 component_to_parent_y (0) - 1,
394 grid_spacing() + _height * tan (angle()) + 2,
400 double const x = channel_x (bc);
401 double const lc = _longest_channel_name + name_pad();
402 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
404 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
406 _body->queue_draw_area (
407 component_to_parent_x (x) - 1,
408 component_to_parent_y (_height - h) - 1,
409 grid_spacing() + lc * cos (angle()) + 2,
413 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
415 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
417 _body->queue_draw_area (
418 component_to_parent_x (x_) - 1,
419 component_to_parent_y (0) - 1,
420 grid_spacing() + lc * cos (angle()) + 2,
429 ARDOUR::BundleChannel
430 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
432 uint32_t const cx = p - (_height - o) * tan (angle ());
433 return PortMatrixComponent::position_to_channel (cx, o, group);
437 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
439 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
442 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
443 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
450 _matrix->popup_menu (
452 ARDOUR::BundleChannel (),
459 PortMatrixColumnLabels::motion (double x, double y)
461 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
464 _body->set_mouseover (PortMatrixNode ());
468 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
471 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
472 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
475 /* if the mouse is over a bundle name, highlight all channels in the bundle */
477 list<PortMatrixNode> n;
479 for (uint32_t i = 0; i < w.bundle->nchannels(); ++i) {
480 ARDOUR::BundleChannel const bc (w.bundle, i);
481 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
484 _body->set_mouseover (n);
488 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));