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;
48 /* height of highest bit of text (apart from group names) */
50 /* width of the whole thing */
53 /* Compute dimensions using all port groups, so that we allow for the largest and hence
54 we can change between visible groups without the size of the labels jumping around.
57 for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
58 PortGroup::BundleList const c = _matrix->columns()->bundles();
59 for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
61 cairo_text_extents_t ext;
62 cairo_text_extents (cr, j->bundle->name().c_str(), &ext);
63 if (ext.width > _longest_bundle_name) {
64 _longest_bundle_name = ext.width;
67 if (ext.height > _highest_text) {
68 _highest_text = ext.height;
71 for (uint32_t k = 0; k < j->bundle->nchannels (); ++k) {
75 j->bundle->channel_name (k).c_str(),
79 if (ext.width > _longest_channel_name) {
80 _longest_channel_name = ext.width;
83 if (ext.height > _highest_text) {
84 _highest_text = ext.height;
89 _width += group_size (*i) * grid_spacing ();
93 gdk_pixmap_unref (pm);
95 /* height of the whole thing */
97 int a = _longest_bundle_name + 4 * name_pad();
98 if (!_matrix->show_only_bundles()) {
99 a += _longest_channel_name;
102 _height = a * sin (angle()) + _highest_text * cos (angle());
103 _overhang = _height / tan (angle ());
108 PortMatrixColumnLabels::basic_text_x_pos (int) const
110 return grid_spacing() / 2 +
111 _highest_text / (2 * sin (angle ()));
115 PortMatrixColumnLabels::render (cairo_t* cr)
119 set_source_rgb (cr, background_colour());
120 cairo_rectangle (cr, 0, 0, _width, _height);
123 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
128 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
129 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
131 Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N);
132 render_bundle_name (cr, background_colour (), c, x, 0, i->bundle);
134 if (_matrix->show_only_bundles()) {
137 x += i->bundle->nchannels () * grid_spacing();
145 if (!_matrix->show_only_bundles()) {
149 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
151 for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) {
152 Gdk::Color c = i->has_colour ? i->colour : get_a_bundle_colour (N);
153 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel (i->bundle, j));
163 PortMatrixColumnLabels::component_to_parent_x (double x) const
165 return x - _body->xoffset() + _parent_rectangle.get_x();
169 PortMatrixColumnLabels::parent_to_component_x (double x) const
171 return x + _body->xoffset() - _parent_rectangle.get_x();
175 PortMatrixColumnLabels::component_to_parent_y (double y) const
177 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
178 return y + _parent_rectangle.get_y();
182 PortMatrixColumnLabels::parent_to_component_y (double y) const
184 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
185 return y - _parent_rectangle.get_y();
189 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
191 list<PortMatrixNode> const m = _body->mouseover ();
192 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
194 ARDOUR::BundleChannel c = i->column;
195 ARDOUR::BundleChannel r = i->row;
197 if (c.bundle && r.bundle) {
198 add_channel_highlight (c);
199 } else if (c.bundle) {
200 _body->highlight_associated_channels (_matrix->column_index(), c);
205 vector<pair<double, double> >
206 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
208 vector<pair<double, double> > shape;
210 double const lc = _longest_channel_name + name_pad();
211 double const w = grid_spacing();
213 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
215 double x_ = xoff + _height / tan (angle()) + w;
217 shape.push_back (make_pair (x_, y_));
219 shape.push_back (make_pair (x_, y_));
220 x_ -= lc * cos (angle());
221 y_ += lc * sin (angle());
222 shape.push_back (make_pair (x_, y_));
223 x_ += w * pow (sin (angle()), 2);
224 y_ += w * sin (angle()) * cos (angle());
225 shape.push_back (make_pair (x_, y_));
230 double y_ = yoff + _height;
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_ -= grid_spacing() * pow (sin (angle()), 2);
238 y_ -= grid_spacing() * sin (angle()) * cos (angle());
239 shape.push_back (make_pair (x_, y_));
246 PortMatrixColumnLabels::render_bundle_name (
247 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
250 set_source_rgb (cr, bg_colour);
253 if (_matrix->show_only_bundles()) {
256 w = b->nchannels() * grid_spacing();
265 cairo_move_to (cr, x_, y_);
267 cairo_line_to (cr, x_, y_);
268 x_ += _height / tan (angle ());
270 cairo_line_to (cr, x_, y_);
272 cairo_line_to (cr, x_, y_);
273 cairo_line_to (cr, xoff, y);
274 cairo_fill_preserve (cr);
275 set_source_rgb (cr, fg_colour);
276 cairo_set_line_width (cr, label_border_width());
279 set_source_rgb (cr, text_colour());
281 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
284 if (_matrix->show_only_bundles()) {
287 rl = 3 * name_pad() + _longest_channel_name;
291 xoff + basic_text_x_pos (0) + rl * cos (angle()),
292 yoff + _height - rl * sin (angle())
299 xoff + basic_text_x_pos (0) + name_pad() * cos (angle ()),
300 yoff + _height - name_pad() * sin (angle())
305 cairo_rotate (cr, -angle());
306 cairo_show_text (cr, b->name().c_str());
311 PortMatrixColumnLabels::render_channel_name (
312 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
315 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
317 cairo_move_to (cr, shape[0].first, shape[0].second);
318 for (uint32_t i = 1; i < 4; ++i) {
319 cairo_line_to (cr, shape[i].first, shape[i].second);
321 cairo_line_to (cr, shape[0].first, shape[0].second);
323 set_source_rgb (cr, bg_colour);
324 cairo_fill_preserve (cr);
325 set_source_rgb (cr, fg_colour);
326 cairo_set_line_width (cr, label_border_width());
329 set_source_rgb (cr, text_colour());
331 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
335 xoff + basic_text_x_pos(bc.channel),
336 yoff + _height - name_pad() * sin (angle())
341 double const rl = 3 * name_pad() + _longest_bundle_name;
344 xoff + basic_text_x_pos(bc.channel) + rl * cos (angle ()),
345 yoff + _height - rl * sin (angle())
349 if (bc.bundle->nchannels() > 1) {
351 /* only plot the name if the bundle has more than one channel;
352 the name of a single channel is assumed to be redundant */
355 cairo_rotate (cr, -angle());
359 bc.bundle->channel_name(bc.channel).c_str()
367 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
369 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
373 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
379 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
385 if (_matrix->show_only_bundles()) {
387 _body->queue_draw_area (
388 component_to_parent_x (channel_x (bc)) - 1,
389 component_to_parent_y (0) - 1,
390 grid_spacing() + _height * tan (angle()) + 2,
396 double const x = channel_x (bc);
397 double const lc = _longest_channel_name + name_pad();
398 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
400 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
402 _body->queue_draw_area (
403 component_to_parent_x (x) - 1,
404 component_to_parent_y (_height - h) - 1,
405 grid_spacing() + lc * cos (angle()) + 2,
409 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
411 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
413 _body->queue_draw_area (
414 component_to_parent_x (x_) - 1,
415 component_to_parent_y (0) - 1,
416 grid_spacing() + lc * cos (angle()) + 2,
425 ARDOUR::BundleChannel
426 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
428 uint32_t const cx = p - (_height - o) * tan (angle ());
429 return PortMatrixComponent::position_to_channel (cx, o, group);
433 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t)
435 ARDOUR::BundleChannel const gc = position_to_channel (x, y, _matrix->visible_columns());
438 _matrix->popup_menu (
440 ARDOUR::BundleChannel (),
447 PortMatrixColumnLabels::motion (double x, double y)
449 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
452 _body->set_mouseover (PortMatrixNode ());
456 uint32_t const bh = _longest_channel_name * sin (angle ()) + _highest_text / cos (angle ());
459 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
460 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
463 /* if the mouse is over a bundle name, highlight all channels in the bundle */
465 list<PortMatrixNode> n;
467 for (uint32_t i = 0; i < w.bundle->nchannels(); ++i) {
468 ARDOUR::BundleChannel const bc (w.bundle, i);
469 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
472 _body->set_mouseover (n);
476 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));