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().n_total(); ++k
) {
59 if (!_matrix
->should_show ((*j
)->bundle
->channel_type(k
))) {
63 cairo_text_extents_t ext
;
64 cairo_text_extents (cr
, (*j
)->bundle
->channel_name(k
).c_str(), &ext
);
65 if (ext
.width
> _longest_port_name
) {
66 _longest_port_name
= ext
.width
;
70 cairo_text_extents_t ext
;
71 cairo_text_extents (cr
, (*j
)->bundle
->name().c_str(), &ext
);
72 if (ext
.width
> _longest_bundle_name
) {
73 _longest_bundle_name
= ext
.width
;
79 if (_matrix
->visible_rows()) {
80 _height
= group_size (_matrix
->visible_rows()) * grid_spacing ();
88 _width
= _longest_bundle_name
+
91 if (!_matrix
->show_only_bundles()) {
92 _width
+= _longest_port_name
;
93 _width
+= name_pad() * 2;
99 PortMatrixRowLabels::render (cairo_t
* cr
)
103 set_source_rgb (cr
, background_colour());
104 cairo_rectangle (cr
, 0, 0, _width
, _height
);
107 /* BUNDLE AND PORT NAMES */
113 PortGroup::BundleList
const & bundles
= _matrix
->visible_rows()->bundles ();
114 for (PortGroup::BundleList::const_iterator i
= bundles
.begin(); i
!= bundles
.end(); ++i
) {
115 render_bundle_name (cr
, background_colour (), (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (N
), 0, y
, (*i
)->bundle
);
117 if (!_matrix
->show_only_bundles()) {
118 uint32_t const N
= _matrix
->count_of_our_type ((*i
)->bundle
->nchannels());
119 for (uint32_t j
= 0; j
< N
; ++j
) {
120 Gdk::Color c
= (*i
)->has_colour
? (*i
)->colour
: get_a_bundle_colour (M
);
121 render_channel_name (cr
, background_colour (), c
, 0, y
, ARDOUR::BundleChannel ((*i
)->bundle
, j
));
127 y
+= grid_spacing ();
139 PortMatrixRowLabels::button_press (double x
, double y
, int b
, uint32_t t
, guint
)
141 ARDOUR::BundleChannel w
= position_to_channel (y
, x
, _matrix
->visible_rows());
144 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& x
> (_longest_port_name
+ name_pad() * 2)) ||
145 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& x
< (_longest_bundle_name
+ name_pad() * 2))
153 _matrix
->popup_menu (
154 ARDOUR::BundleChannel (),
162 PortMatrixRowLabels::component_to_parent_x (double x
) const
164 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
165 return x
+ _parent_rectangle
.get_x();
169 PortMatrixRowLabels::parent_to_component_x (double x
) const
171 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
172 return x
- _parent_rectangle
.get_x();
176 PortMatrixRowLabels::component_to_parent_y (double y
) const
178 return y
- _body
->yoffset() + _parent_rectangle
.get_y();
182 PortMatrixRowLabels::parent_to_component_y (double y
) const
184 return y
+ _body
->yoffset() - _parent_rectangle
.get_y();
189 PortMatrixRowLabels::bundle_name_x () const
193 if (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& !_matrix
->show_only_bundles ()) {
194 x
= _longest_port_name
+ name_pad() * 2;
201 PortMatrixRowLabels::port_name_x () const
203 if (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
) {
204 return _longest_bundle_name
+ name_pad() * 2;
213 PortMatrixRowLabels::render_bundle_name (
214 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, boost::shared_ptr
<ARDOUR::Bundle
> b
217 double const x
= bundle_name_x ();
219 int const n
= _matrix
->show_only_bundles() ? 1 : _matrix
->count_of_our_type_min_1 (b
->nchannels());
220 set_source_rgb (cr
, bg_colour
);
221 cairo_rectangle (cr
, xoff
+ x
, yoff
, _longest_bundle_name
+ name_pad() * 2, grid_spacing() * n
);
222 cairo_fill_preserve (cr
);
223 set_source_rgb (cr
, fg_colour
);
224 cairo_set_line_width (cr
, label_border_width ());
227 cairo_text_extents_t ext
;
228 cairo_text_extents (cr
, b
->name().c_str(), &ext
);
229 double const off
= (grid_spacing() - ext
.height
) / 2;
231 set_source_rgb (cr
, text_colour());
232 cairo_move_to (cr
, xoff
+ x
+ name_pad(), yoff
+ name_pad() + off
);
233 cairo_show_text (cr
, b
->name().c_str());
237 PortMatrixRowLabels::render_channel_name (
238 cairo_t
* cr
, Gdk::Color fg_colour
, Gdk::Color bg_colour
, double xoff
, double yoff
, ARDOUR::BundleChannel
const& bc
241 set_source_rgb (cr
, bg_colour
);
242 cairo_rectangle (cr
, port_name_x() + xoff
, yoff
, _longest_port_name
+ name_pad() * 2, grid_spacing());
243 cairo_fill_preserve (cr
);
244 set_source_rgb (cr
, fg_colour
);
245 cairo_set_line_width (cr
, label_border_width ());
248 if (_matrix
->count_of_our_type (bc
.bundle
->nchannels()) > 1) {
250 /* only plot the name if the bundle has more than one channel;
251 the name of a single channel is assumed to be redundant */
253 cairo_text_extents_t ext
;
254 cairo_text_extents (cr
, bc
.bundle
->channel_name(bc
.channel
).c_str(), &ext
);
255 double const off
= (grid_spacing() - ext
.height
) / 2;
257 set_source_rgb (cr
, text_colour());
258 cairo_move_to (cr
, port_name_x() + xoff
+ name_pad(), yoff
+ name_pad() + off
);
259 cairo_show_text (cr
, bc
.bundle
->channel_name(bc
.channel
).c_str());
264 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel
const &) const
270 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel
const& bc
) const
272 return channel_to_position (bc
, _matrix
->visible_rows()) * grid_spacing ();
276 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel
const & bc
)
280 if (_matrix
->show_only_bundles()) {
281 _body
->queue_draw_area (
282 component_to_parent_x (bundle_name_x()) - 1,
283 component_to_parent_y (channel_y (bc
)) - 1,
284 _longest_bundle_name
+ name_pad() * 2 + 2,
288 _body
->queue_draw_area (
289 component_to_parent_x (port_name_x()) - 1,
290 component_to_parent_y (channel_y (bc
)) - 1,
291 _longest_port_name
+ name_pad() * 2 + 2,
300 PortMatrixRowLabels::mouseover_changed (list
<PortMatrixNode
> const &)
302 list
<PortMatrixNode
> const m
= _body
->mouseover ();
303 for (list
<PortMatrixNode
>::const_iterator i
= m
.begin(); i
!= m
.end(); ++i
) {
305 ARDOUR::BundleChannel c
= i
->column
;
306 ARDOUR::BundleChannel r
= i
->row
;
308 if (PortMatrix::bundle_with_channels (c
.bundle
) && PortMatrix::bundle_with_channels (r
.bundle
)) {
309 add_channel_highlight (r
);
310 } else if (r
.bundle
) {
311 _body
->highlight_associated_channels (_matrix
->row_index(), r
);
317 PortMatrixRowLabels::motion (double x
, double y
)
319 ARDOUR::BundleChannel
const w
= position_to_channel (y
, x
, _matrix
->visible_rows());
321 uint32_t const bw
= _longest_bundle_name
+ 2 * name_pad();
328 (_matrix
->arrangement() == PortMatrix::LEFT_TO_BOTTOM
&& x
< bw
) ||
329 (_matrix
->arrangement() == PortMatrix::TOP_TO_RIGHT
&& x
> (_width
- bw
) && x
< _width
)
333 /* if the mouse is over a bundle name, highlight all channels in the bundle */
335 list
<PortMatrixNode
> n
;
337 for (uint32_t i
= 0; i
< w
.bundle
->nchannels().n_total(); ++i
) {
339 if (!_matrix
->should_show (w
.bundle
->channel_type(i
))) {
343 ARDOUR::BundleChannel
const bc (w
.bundle
, i
);
344 n
.push_back (PortMatrixNode (bc
, ARDOUR::BundleChannel ()));
347 _body
->set_mouseover (n
);
350 } else if (x
< _width
) {
352 _body
->set_mouseover (PortMatrixNode (w
, ARDOUR::BundleChannel ()));
360 /* not over any bundle */
361 _body
->set_mouseover (PortMatrixNode ());