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 <boost/weak_ptr.hpp>
22 #include <cairo/cairo.h>
23 #include "ardour/bundle.h"
24 #include "port_matrix_row_labels.h"
25 #include "port_matrix.h"
26 #include "port_matrix_body.h"
32 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix
* m
, PortMatrixBody
* b
)
33 : PortMatrixLabels (m
, b
)
39 PortMatrixRowLabels::compute_dimensions ()
41 GdkPixmap
* pm
= gdk_pixmap_new (NULL
, 1, 1, 24);
42 gdk_drawable_set_colormap (pm
, gdk_colormap_get_system());
43 cairo_t
* cr
= gdk_cairo_create (pm
);
45 _longest_port_name
= 0;
46 _longest_bundle_name
= 0;
48 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
49 we can change between visible groups without the size of the labels jumping around.
52 for (PortGroupList::List::const_iterator i
= _matrix
->rows()->begin(); i
!= _matrix
->rows()->end(); ++i
) {
54 PortGroup::BundleList
const r
= (*i
)->bundles ();
55 for (PortGroup::BundleList::const_iterator j
= r
.begin(); j
!= r
.end(); ++j
) {
57 for (uint32_t k
= 0; k
< (*j
)->bundle
->nchannels(); ++k
) {
58 cairo_text_extents_t ext
;
59 cairo_text_extents (cr
, (*j
)->bundle
->channel_name(k
).c_str(), &ext
);
60 if (ext
.width
> _longest_port_name
) {
61 _longest_port_name
= ext
.width
;
65 cairo_text_extents_t ext
;
66 cairo_text_extents (cr
, (*j
)->bundle
->name().c_str(), &ext
);
67 if (ext
.width
> _longest_bundle_name
) {
68 _longest_bundle_name
= ext
.width
;
74 if (_matrix
->visible_rows()) {
75 _height
= group_size (_matrix
->visible_rows()) * grid_spacing ();
83 _width
= _longest_bundle_name
+
86 if (!_matrix
->show_only_bundles()) {
87 _width
+= _longest_port_name
;
88 _width
+= name_pad() * 2;
94 PortMatrixRowLabels::render (cairo_t
* cr
)
98 set_source_rgb (cr
, background_colour());
99 cairo_rectangle (cr
, 0, 0, _width
, _height
);
102 /* BUNDLE AND PORT NAMES */
108 PortGroup::BundleList
const & bundles
= _matrix
->visible_rows()->bundles ();
109 for (PortGroup::BundleList::const_iterator i
= bundles
.begin(); i
!= bundles
.end(); ++i
) {
110 render_bundle_name (cr
, background_colour (), (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (N
), 0, y
, (*i
)->bundle
);
112 if (!_matrix
->show_only_bundles()) {
113 for (uint32_t j
= 0; j
< (*i
)->bundle
->nchannels(); ++j
) {
114 Gdk::Color c
= (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (M
);
115 render_channel_name (cr
, background_colour (), c
, 0, y
, ARDOUR::BundleChannel ((*i
)->bundle
, j
));
128 PortMatrixRowLabels::button_press (double x
, double y
, int b
, uint32_t t
, guint
)
130 ARDOUR::BundleChannel w
= position_to_channel (y
, x
, _matrix
->visible_rows());
133 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& x
> (_longest_port_name
+ name_pad() * 2)) ||
134 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& x
< (_longest_bundle_name
+ name_pad() * 2))
142 _matrix
->popup_menu (
143 ARDOUR::BundleChannel (),
151 PortMatrixRowLabels::component_to_parent_x (double x
) const
153 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
154 return x
+ _parent_rectangle
.get_x();
158 PortMatrixRowLabels::parent_to_component_x (double x
) const
160 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
161 return x
- _parent_rectangle
.get_x();
165 PortMatrixRowLabels::component_to_parent_y (double y
) const
167 return y
- _body
->yoffset() + _parent_rectangle
.get_y();
171 PortMatrixRowLabels::parent_to_component_y (double y
) const
173 return y
+ _body
->yoffset() - _parent_rectangle
.get_y();
178 PortMatrixRowLabels::bundle_name_x () const
182 if (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& !_matrix
->show_only_bundles ()) {
183 x
= _longest_port_name
+ name_pad() * 2;
190 PortMatrixRowLabels::port_name_x () const
192 if (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
) {
193 return _longest_bundle_name
+ name_pad() * 2;
202 PortMatrixRowLabels::render_bundle_name (
203 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, boost::shared_ptr
<ARDOUR::Bundle
> b
206 double const x
= bundle_name_x ();
208 int const n
= _matrix
->show_only_bundles() ? 1 : b
->nchannels();
209 set_source_rgb (cr
, bg_colour
);
210 cairo_rectangle (cr
, xoff
+ x
, yoff
, _longest_bundle_name
+ name_pad() * 2, grid_spacing() * n
);
211 cairo_fill_preserve (cr
);
212 set_source_rgb (cr
, fg_colour
);
213 cairo_set_line_width (cr
, label_border_width ());
216 cairo_text_extents_t ext
;
217 cairo_text_extents (cr
, b
->name().c_str(), &ext
);
218 double const off
= (grid_spacing() - ext
.height
) / 2;
220 set_source_rgb (cr
, text_colour());
221 cairo_move_to (cr
, xoff
+ x
+ name_pad(), yoff
+ name_pad() + off
);
222 cairo_show_text (cr
, b
->name().c_str());
226 PortMatrixRowLabels::render_channel_name (
227 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, ARDOUR::BundleChannel
const& bc
230 set_source_rgb (cr
, bg_colour
);
231 cairo_rectangle (cr
, port_name_x() + xoff
, yoff
, _longest_port_name
+ name_pad() * 2, grid_spacing());
232 cairo_fill_preserve (cr
);
233 set_source_rgb (cr
, fg_colour
);
234 cairo_set_line_width (cr
, label_border_width ());
237 cairo_text_extents_t ext
;
238 cairo_text_extents (cr
, bc
.bundle
->channel_name(bc
.channel
).c_str(), &ext
);
239 double const off
= (grid_spacing() - ext
.height
) / 2;
241 if (bc
.bundle
->nchannels() > 1) {
243 /* only plot the name if the bundle has more than one channel;
244 the name of a single channel is assumed to be redundant */
246 set_source_rgb (cr
, text_colour());
247 cairo_move_to (cr
, port_name_x() + xoff
+ name_pad(), yoff
+ name_pad() + off
);
248 cairo_show_text (cr
, bc
.bundle
->channel_name(bc
.channel
).c_str());
253 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel
const &) const
259 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel
const& bc
) const
261 return channel_to_position (bc
, _matrix
->visible_rows()) * grid_spacing ();
265 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel
const & bc
)
269 if (_matrix
->show_only_bundles()) {
270 _body
->queue_draw_area (
271 component_to_parent_x (bundle_name_x()) - 1,
272 component_to_parent_y (channel_y (bc
)) - 1,
273 _longest_bundle_name
+ name_pad() * 2 + 2,
277 _body
->queue_draw_area (
278 component_to_parent_x (port_name_x()) - 1,
279 component_to_parent_y (channel_y (bc
)) - 1,
280 _longest_port_name
+ name_pad() * 2 + 2,
289 PortMatrixRowLabels::mouseover_changed (list
<PortMatrixNode
> const &)
291 list
<PortMatrixNode
> const m
= _body
->mouseover ();
292 for (list
<PortMatrixNode
>::const_iterator i
= m
.begin(); i
!= m
.end(); ++i
) {
294 ARDOUR::BundleChannel c
= i
->column
;
295 ARDOUR::BundleChannel r
= i
->row
;
297 if (c
.bundle
&& r
.bundle
) {
298 add_channel_highlight (r
);
299 } else if (r
.bundle
) {
300 _body
->highlight_associated_channels (_matrix
->row_index(), r
);
306 PortMatrixRowLabels::motion (double x
, double y
)
308 ARDOUR::BundleChannel
const w
= position_to_channel (y
, x
, _matrix
->visible_rows());
310 uint32_t const bw
= _longest_bundle_name
+ 2 * name_pad();
317 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& x
< bw
) ||
318 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& x
> (_width
- bw
) && x
< _width
)
322 /* if the mouse is over a bundle name, highlight all channels in the bundle */
324 list
<PortMatrixNode
> n
;
326 for (uint32_t i
= 0; i
< w
.bundle
->nchannels(); ++i
) {
327 ARDOUR::BundleChannel
const bc (w
.bundle
, i
);
328 n
.push_back (PortMatrixNode (bc
, ARDOUR::BundleChannel ()));
331 _body
->set_mouseover (n
);
334 } else if (x
< _width
) {
336 _body
->set_mouseover (PortMatrixNode (w
, ARDOUR::BundleChannel ()));
344 /* not over any bundle */
345 _body
->set_mouseover (PortMatrixNode ());