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 (); ++k
) {
69 (*j
)->bundle
->channel_name (k
).c_str(),
73 if (ext
.width
> _longest_channel_name
) {
74 _longest_channel_name
= ext
.width
;
81 cairo_text_extents_t ext
;
82 cairo_text_extents (cr
, X_("AQRjpy"), &ext
);
83 _text_height
= ext
.height
;
84 _descender_height
= ext
.height
+ ext
.y_bearing
;
86 /* width of the whole thing */
87 if (_matrix
->visible_columns()) {
88 _width
= group_size (_matrix
->visible_columns()) * grid_spacing ();
96 /* height of the whole thing */
98 int a
= _longest_bundle_name
+ 4 * name_pad();
99 if (!_matrix
->show_only_bundles()) {
100 a
+= _longest_channel_name
;
103 _height
= a
* sin (angle()) + _text_height
* cos (angle());
104 _overhang
= _height
/ tan (angle ());
109 PortMatrixColumnLabels::basic_text_x_pos (int) const
111 return grid_spacing() / 2 +
112 _text_height
/ (2 * sin (angle ()));
116 PortMatrixColumnLabels::render (cairo_t
* cr
)
120 set_source_rgb (cr
, background_colour());
121 cairo_rectangle (cr
, 0, 0, _width
, _height
);
124 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
129 PortGroup::BundleList
const & bundles
= _matrix
->visible_columns()->bundles ();
130 for (PortGroup::BundleList::const_iterator i
= bundles
.begin (); i
!= bundles
.end(); ++i
) {
132 Gdk::Color c
= (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (N
);
133 render_bundle_name (cr
, background_colour (), c
, x
, 0, (*i
)->bundle
);
135 if (_matrix
->show_only_bundles()) {
138 x
+= (*i
)->bundle
->nchannels () * grid_spacing();
146 if (!_matrix
->show_only_bundles()) {
150 for (PortGroup::BundleList::const_iterator i
= bundles
.begin (); i
!= bundles
.end(); ++i
) {
152 for (uint32_t j
= 0; j
< (*i
)->bundle
->nchannels(); ++j
) {
153 Gdk::Color c
= (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (N
);
154 render_channel_name (cr
, background_colour (), c
, x
, 0, ARDOUR::BundleChannel ((*i
)->bundle
, j
));
164 PortMatrixColumnLabels::component_to_parent_x (double x
) const
166 return x
- _body
->xoffset() + _parent_rectangle
.get_x();
170 PortMatrixColumnLabels::parent_to_component_x (double x
) const
172 return x
+ _body
->xoffset() - _parent_rectangle
.get_x();
176 PortMatrixColumnLabels::component_to_parent_y (double y
) const
178 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
179 return y
+ _parent_rectangle
.get_y();
183 PortMatrixColumnLabels::parent_to_component_y (double y
) const
185 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
186 return y
- _parent_rectangle
.get_y();
190 PortMatrixColumnLabels::mouseover_changed (list
<PortMatrixNode
> const &)
192 list
<PortMatrixNode
> const m
= _body
->mouseover ();
193 for (list
<PortMatrixNode
>::const_iterator i
= m
.begin(); i
!= m
.end(); ++i
) {
195 ARDOUR::BundleChannel c
= i
->column
;
196 ARDOUR::BundleChannel r
= i
->row
;
198 if (c
.bundle
&& r
.bundle
) {
199 add_channel_highlight (c
);
200 } else if (c
.bundle
) {
201 _body
->highlight_associated_channels (_matrix
->column_index(), c
);
206 vector
<pair
<double, double> >
207 PortMatrixColumnLabels::port_name_shape (double xoff
, double yoff
) const
209 vector
<pair
<double, double> > shape
;
211 double const lc
= _longest_channel_name
+ name_pad();
212 double const w
= grid_spacing();
214 if (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
) {
216 double x_
= xoff
+ _height
/ tan (angle()) + w
;
218 shape
.push_back (make_pair (x_
, y_
));
220 shape
.push_back (make_pair (x_
, y_
));
221 x_
-= lc
* cos (angle());
222 y_
+= lc
* sin (angle());
223 shape
.push_back (make_pair (x_
, y_
));
224 x_
+= w
* pow (sin (angle()), 2);
225 y_
+= w
* sin (angle()) * cos (angle());
226 shape
.push_back (make_pair (x_
, y_
));
231 double y_
= yoff
+ _height
;
232 shape
.push_back (make_pair (x_
, y_
));
234 shape
.push_back (make_pair (x_
, y_
));
235 x_
+= lc
* cos (angle());
236 y_
-= lc
* sin (angle());
237 shape
.push_back (make_pair (x_
, y_
));
238 x_
-= grid_spacing() * pow (sin (angle()), 2);
239 y_
-= grid_spacing() * sin (angle()) * cos (angle());
240 shape
.push_back (make_pair (x_
, y_
));
247 PortMatrixColumnLabels::render_bundle_name (
248 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, boost::shared_ptr
<ARDOUR::Bundle
> b
251 set_source_rgb (cr
, bg_colour
);
254 if (_matrix
->show_only_bundles()) {
257 w
= b
->nchannels() * grid_spacing();
266 cairo_move_to (cr
, x_
, y_
);
268 cairo_line_to (cr
, x_
, y_
);
269 x_
+= _height
/ tan (angle ());
271 cairo_line_to (cr
, x_
, y_
);
273 cairo_line_to (cr
, x_
, y_
);
274 cairo_line_to (cr
, xoff
, y
);
275 cairo_fill_preserve (cr
);
276 set_source_rgb (cr
, fg_colour
);
277 cairo_set_line_width (cr
, label_border_width());
280 set_source_rgb (cr
, text_colour());
282 double const q
= ((grid_spacing() * sin (angle())) - _text_height
) / 2 + _descender_height
;
284 if (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
) {
287 if (_matrix
->show_only_bundles()) {
290 rl
= 3 * name_pad() + _longest_channel_name
;
294 xoff
+ grid_spacing() - q
* sin (angle ()) + rl
* cos (angle()),
295 yoff
+ _height
- q
* cos (angle ()) - rl
* sin (angle())
302 xoff
+ grid_spacing() - q
* sin (angle ()),
303 yoff
+ _height
- q
* cos (angle ())
308 cairo_rotate (cr
, -angle());
309 cairo_show_text (cr
, b
->name().c_str());
314 PortMatrixColumnLabels::render_channel_name (
315 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, ARDOUR::BundleChannel
const &bc
318 vector
<pair
<double, double> > const shape
= port_name_shape (xoff
, yoff
);
320 cairo_move_to (cr
, shape
[0].first
, shape
[0].second
);
321 for (uint32_t i
= 1; i
< 4; ++i
) {
322 cairo_line_to (cr
, shape
[i
].first
, shape
[i
].second
);
324 cairo_line_to (cr
, shape
[0].first
, shape
[0].second
);
326 set_source_rgb (cr
, bg_colour
);
327 cairo_fill_preserve (cr
);
328 set_source_rgb (cr
, fg_colour
);
329 cairo_set_line_width (cr
, label_border_width());
332 set_source_rgb (cr
, text_colour());
334 double const q
= ((grid_spacing() * sin (angle())) - _text_height
) / 2 + _descender_height
;
336 if (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
) {
340 xoff
+ grid_spacing() - q
* sin (angle ()),
341 yoff
+ _height
- q
* cos (angle ())
347 double const rl
= 3 * name_pad() + _longest_bundle_name
;
350 xoff
+ grid_spacing() - q
* sin (angle ()) + rl
* cos (angle ()),
351 yoff
+ _height
- q
* cos (angle ()) - rl
* sin (angle())
355 if (bc
.bundle
->nchannels() > 1) {
357 /* only plot the name if the bundle has more than one channel;
358 the name of a single channel is assumed to be redundant */
361 cairo_rotate (cr
, -angle());
365 bc
.bundle
->channel_name(bc
.channel
).c_str()
373 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel
const &bc
) const
375 return channel_to_position (bc
, _matrix
->visible_columns()) * grid_spacing ();
379 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel
const &) const
385 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel
const & bc
)
391 if (_matrix
->show_only_bundles()) {
393 _body
->queue_draw_area (
394 component_to_parent_x (channel_x (bc
)) - 1,
395 component_to_parent_y (0) - 1,
396 grid_spacing() + _height
* tan (angle()) + 2,
402 double const x
= channel_x (bc
);
403 double const lc
= _longest_channel_name
+ name_pad();
404 double const h
= lc
* sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
406 if (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
) {
408 _body
->queue_draw_area (
409 component_to_parent_x (x
) - 1,
410 component_to_parent_y (_height
- h
) - 1,
411 grid_spacing() + lc
* cos (angle()) + 2,
415 } else if (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
) {
417 double const x_
= x
+ _height
/ tan (angle()) - lc
* cos (angle());
419 _body
->queue_draw_area (
420 component_to_parent_x (x_
) - 1,
421 component_to_parent_y (0) - 1,
422 grid_spacing() + lc
* cos (angle()) + 2,
431 ARDOUR::BundleChannel
432 PortMatrixColumnLabels::position_to_channel (double p
, double o
, boost::shared_ptr
<const PortGroup
> group
) const
434 uint32_t const cx
= p
- (_height
- o
) * tan (angle ());
435 return PortMatrixComponent::position_to_channel (cx
, o
, group
);
439 PortMatrixColumnLabels::button_press (double x
, double y
, int b
, uint32_t t
, guint
)
441 ARDOUR::BundleChannel w
= position_to_channel (x
, y
, _matrix
->visible_columns());
444 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& y
> (_height
- _longest_bundle_name
* sin (angle ()))) ||
445 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& y
< (_longest_bundle_name
* sin (angle ())))
452 _matrix
->popup_menu (
454 ARDOUR::BundleChannel (),
461 PortMatrixColumnLabels::motion (double x
, double y
)
463 ARDOUR::BundleChannel
const w
= position_to_channel (x
, y
, _matrix
->visible_columns());
466 _body
->set_mouseover (PortMatrixNode ());
470 uint32_t const bh
= _longest_channel_name
* sin (angle ()) + _text_height
/ cos (angle ());
473 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& y
> bh
) ||
474 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& y
< (_height
- bh
))
477 /* if the mouse is over a bundle name, highlight all channels in the bundle */
479 list
<PortMatrixNode
> n
;
481 for (uint32_t i
= 0; i
< w
.bundle
->nchannels(); ++i
) {
482 ARDOUR::BundleChannel
const bc (w
.bundle
, i
);
483 n
.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc
));
486 _body
->set_mouseover (n
);
490 _body
->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w
));