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>
23 #include "gtkmm2ext/keyboard.h"
24 #include "ardour/bundle.h"
25 #include "port_matrix_row_labels.h"
26 #include "port_matrix.h"
27 #include "port_matrix_body.h"
33 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b)
34 : PortMatrixLabels (m, b)
40 PortMatrixRowLabels::compute_dimensions ()
42 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
43 cairo_t* cr = cairo_create (surface);
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 ();
86 cairo_surface_destroy (surface);
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 ARDOUR::BundleChannel bc (
123 (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
126 render_channel_name (cr, background_colour (), c, 0, y, bc);
132 y += grid_spacing ();
144 PortMatrixRowLabels::button_press (double x, double y, GdkEventButton* ev)
146 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
149 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
150 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
156 if (Gtkmm2ext::Keyboard::is_delete_event (ev) && w.channel != -1) {
157 _matrix->remove_channel (w);
158 } else if (ev->button == 3) {
159 _matrix->popup_menu (
160 ARDOUR::BundleChannel (),
168 PortMatrixRowLabels::component_to_parent_x (double x) const
170 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
171 return x + _parent_rectangle.get_x();
175 PortMatrixRowLabels::parent_to_component_x (double x) const
177 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
178 return x - _parent_rectangle.get_x();
182 PortMatrixRowLabels::component_to_parent_y (double y) const
184 return y - _body->yoffset() + _parent_rectangle.get_y();
188 PortMatrixRowLabels::parent_to_component_y (double y) const
190 return y + _body->yoffset() - _parent_rectangle.get_y();
195 PortMatrixRowLabels::bundle_name_x () const
199 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
200 x = _longest_port_name + name_pad() * 2;
207 PortMatrixRowLabels::port_name_x () const
209 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
210 return _longest_bundle_name + name_pad() * 2;
219 PortMatrixRowLabels::render_bundle_name (
220 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
223 double const x = bundle_name_x ();
225 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
226 set_source_rgb (cr, bg_colour);
227 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
228 cairo_fill_preserve (cr);
229 set_source_rgb (cr, fg_colour);
230 cairo_set_line_width (cr, label_border_width ());
233 cairo_text_extents_t ext;
234 cairo_text_extents (cr, b->name().c_str(), &ext);
235 double const off = (grid_spacing() - ext.height) / 2;
237 set_source_rgb (cr, text_colour());
238 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
239 cairo_show_text (cr, b->name().c_str());
243 PortMatrixRowLabels::render_channel_name (
244 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
247 set_source_rgb (cr, bg_colour);
248 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
249 cairo_fill_preserve (cr);
250 set_source_rgb (cr, fg_colour);
251 cairo_set_line_width (cr, label_border_width ());
254 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
256 /* only plot the name if the bundle has more than one channel;
257 the name of a single channel is assumed to be redundant */
259 cairo_text_extents_t ext;
260 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
261 double const off = (grid_spacing() - ext.height) / 2;
263 set_source_rgb (cr, text_colour());
264 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
265 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
270 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
276 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
278 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
282 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
286 if (_matrix->show_only_bundles()) {
287 _body->queue_draw_area (
288 component_to_parent_x (bundle_name_x()) - 1,
289 component_to_parent_y (channel_y (bc)) - 1,
290 _longest_bundle_name + name_pad() * 2 + 2,
294 _body->queue_draw_area (
295 component_to_parent_x (port_name_x()) - 1,
296 component_to_parent_y (channel_y (bc)) - 1,
297 _longest_port_name + name_pad() * 2 + 2,
306 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
308 list<PortMatrixNode> const m = _body->mouseover ();
309 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
311 ARDOUR::BundleChannel c = i->column;
312 ARDOUR::BundleChannel r = i->row;
314 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
315 add_channel_highlight (r);
316 } else if (r.bundle) {
317 _body->highlight_associated_channels (_matrix->row_index(), r);
323 PortMatrixRowLabels::motion (double x, double y)
325 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
327 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
334 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
335 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
339 /* if the mouse is over a bundle name, highlight all channels in the bundle */
341 list<PortMatrixNode> n;
343 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
344 if (!_matrix->should_show (w.bundle->channel_type (i))) {
348 ARDOUR::BundleChannel const bc (w.bundle, i);
349 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
352 _body->set_mouseover (n);
355 } else if (x < _width) {
357 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
365 /* not over any bundle */
366 _body->set_mouseover (PortMatrixNode ());