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 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
42 cairo_t* cr = cairo_create (surface);
44 _longest_port_name = 0;
45 _longest_bundle_name = 0;
47 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
48 we can change between visible groups without the size of the labels jumping around.
51 for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
53 PortGroup::BundleList const r = (*i)->bundles ();
54 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
56 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
58 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
62 cairo_text_extents_t ext;
63 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
64 if (ext.width > _longest_port_name) {
65 _longest_port_name = ext.width;
69 cairo_text_extents_t ext;
70 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
71 if (ext.width > _longest_bundle_name) {
72 _longest_bundle_name = ext.width;
78 if (_matrix->visible_rows()) {
79 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
85 cairo_surface_destroy (surface);
87 _width = _longest_bundle_name +
90 if (!_matrix->show_only_bundles()) {
91 _width += _longest_port_name;
92 _width += name_pad() * 2;
98 PortMatrixRowLabels::render (cairo_t* cr)
102 set_source_rgb (cr, background_colour());
103 cairo_rectangle (cr, 0, 0, _width, _height);
106 /* BUNDLE AND PORT NAMES */
112 PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
113 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
114 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
116 if (!_matrix->show_only_bundles()) {
117 uint32_t const N = _matrix->count_of_our_type ((*i)->bundle->nchannels());
118 for (uint32_t j = 0; j < N; ++j) {
119 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
120 ARDOUR::BundleChannel bc (
122 (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
125 render_channel_name (cr, background_colour (), c, 0, y, bc);
131 y += grid_spacing ();
143 PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t, guint)
145 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
148 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
149 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
157 _matrix->popup_menu (
158 ARDOUR::BundleChannel (),
166 PortMatrixRowLabels::component_to_parent_x (double x) const
168 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
169 return x + _parent_rectangle.get_x();
173 PortMatrixRowLabels::parent_to_component_x (double x) const
175 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
176 return x - _parent_rectangle.get_x();
180 PortMatrixRowLabels::component_to_parent_y (double y) const
182 return y - _body->yoffset() + _parent_rectangle.get_y();
186 PortMatrixRowLabels::parent_to_component_y (double y) const
188 return y + _body->yoffset() - _parent_rectangle.get_y();
193 PortMatrixRowLabels::bundle_name_x () const
197 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
198 x = _longest_port_name + name_pad() * 2;
205 PortMatrixRowLabels::port_name_x () const
207 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
208 return _longest_bundle_name + name_pad() * 2;
217 PortMatrixRowLabels::render_bundle_name (
218 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
221 double const x = bundle_name_x ();
223 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
224 set_source_rgb (cr, bg_colour);
225 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
226 cairo_fill_preserve (cr);
227 set_source_rgb (cr, fg_colour);
228 cairo_set_line_width (cr, label_border_width ());
231 cairo_text_extents_t ext;
232 cairo_text_extents (cr, b->name().c_str(), &ext);
233 double const off = (grid_spacing() - ext.height) / 2;
235 set_source_rgb (cr, text_colour());
236 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
237 cairo_show_text (cr, b->name().c_str());
241 PortMatrixRowLabels::render_channel_name (
242 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
245 set_source_rgb (cr, bg_colour);
246 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
247 cairo_fill_preserve (cr);
248 set_source_rgb (cr, fg_colour);
249 cairo_set_line_width (cr, label_border_width ());
252 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
254 /* only plot the name if the bundle has more than one channel;
255 the name of a single channel is assumed to be redundant */
257 cairo_text_extents_t ext;
258 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
259 double const off = (grid_spacing() - ext.height) / 2;
261 set_source_rgb (cr, text_colour());
262 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
263 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
268 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
274 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
276 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
280 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
284 if (_matrix->show_only_bundles()) {
285 _body->queue_draw_area (
286 component_to_parent_x (bundle_name_x()) - 1,
287 component_to_parent_y (channel_y (bc)) - 1,
288 _longest_bundle_name + name_pad() * 2 + 2,
292 _body->queue_draw_area (
293 component_to_parent_x (port_name_x()) - 1,
294 component_to_parent_y (channel_y (bc)) - 1,
295 _longest_port_name + name_pad() * 2 + 2,
304 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
306 list<PortMatrixNode> const m = _body->mouseover ();
307 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
309 ARDOUR::BundleChannel c = i->column;
310 ARDOUR::BundleChannel r = i->row;
312 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
313 add_channel_highlight (r);
314 } else if (r.bundle) {
315 _body->highlight_associated_channels (_matrix->row_index(), r);
321 PortMatrixRowLabels::motion (double x, double y)
323 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
325 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
332 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
333 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
337 /* if the mouse is over a bundle name, highlight all channels in the bundle */
339 list<PortMatrixNode> n;
341 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
342 if (!_matrix->should_show (w.bundle->channel_type (i))) {
346 ARDOUR::BundleChannel const bc (w.bundle, i);
347 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
350 _body->set_mouseover (n);
353 } else if (x < _width) {
355 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
363 /* not over any bundle */
364 _body->set_mouseover (PortMatrixNode ());