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 "canvas/colors.h"
27 #include "port_matrix_row_labels.h"
28 #include "port_matrix.h"
29 #include "port_matrix_body.h"
34 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b)
35 : PortMatrixLabels (m, b)
41 PortMatrixRowLabels::compute_dimensions ()
43 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
44 cairo_t* cr = cairo_create (surface);
46 _longest_port_name = 0;
47 _longest_bundle_name = 0;
49 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
50 we can change between visible groups without the size of the labels jumping around.
53 for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
55 PortGroup::BundleList const r = (*i)->bundles ();
56 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
58 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
60 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
64 cairo_text_extents_t ext;
65 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
66 if (ext.width > _longest_port_name) {
67 _longest_port_name = ext.width;
71 cairo_text_extents_t ext;
72 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
73 if (ext.width > _longest_bundle_name) {
74 _longest_bundle_name = ext.width;
80 if (_matrix->visible_rows()) {
81 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
87 cairo_surface_destroy (surface);
89 _width = _longest_bundle_name +
92 if (!_matrix->show_only_bundles()) {
93 _width += _longest_port_name;
94 _width += name_pad() * 2;
100 PortMatrixRowLabels::render (cairo_t* cr)
104 set_source_rgb (cr, background_colour());
105 cairo_rectangle (cr, 0, 0, _width, _height);
108 /* BUNDLE AND PORT NAMES */
114 PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
115 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
116 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
118 if (!_matrix->show_only_bundles()) {
119 uint32_t const N = _matrix->count_of_our_type ((*i)->bundle->nchannels());
120 for (uint32_t j = 0; j < N; ++j) {
121 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
122 ARDOUR::BundleChannel bc (
124 (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
127 render_channel_name (cr, background_colour (), c, 0, y, bc);
133 y += grid_spacing ();
145 PortMatrixRowLabels::button_press (double x, double y, GdkEventButton* ev)
147 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
150 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
151 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
157 if (Gtkmm2ext::Keyboard::is_delete_event (ev) && w.channel != -1) {
158 _matrix->remove_channel (w);
159 } else if (ev->button == 3) {
160 _matrix->popup_menu (
161 ARDOUR::BundleChannel (),
169 PortMatrixRowLabels::component_to_parent_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::parent_to_component_x (double x) const
178 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
179 return x - _parent_rectangle.get_x();
183 PortMatrixRowLabels::component_to_parent_y (double y) const
185 return y - _body->yoffset() + _parent_rectangle.get_y();
189 PortMatrixRowLabels::parent_to_component_y (double y) const
191 return y + _body->yoffset() - _parent_rectangle.get_y();
196 PortMatrixRowLabels::bundle_name_x () const
200 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
201 x = _longest_port_name + name_pad() * 2;
208 PortMatrixRowLabels::port_name_x () const
210 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
211 return _longest_bundle_name + name_pad() * 2;
220 PortMatrixRowLabels::render_bundle_name (
221 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
224 double const x = bundle_name_x ();
226 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
227 set_source_rgb (cr, bg_colour);
228 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
229 cairo_fill_preserve (cr);
230 set_source_rgb (cr, fg_colour);
231 cairo_set_line_width (cr, label_border_width ());
234 cairo_text_extents_t ext;
235 cairo_text_extents (cr, b->name().c_str(), &ext);
236 double const off = (grid_spacing() - ext.height) / 2;
238 Gdk::Color textcolor;
239 ARDOUR_UI_UTILS::set_color_from_rgba(textcolor, ArdourCanvas::contrasting_text_color(ARDOUR_UI_UTILS::gdk_color_to_rgba(bg_colour)));
240 set_source_rgb (cr, textcolor);
241 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
242 cairo_show_text (cr, b->name().c_str());
246 PortMatrixRowLabels::render_channel_name (
247 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
250 set_source_rgb (cr, bg_colour);
251 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
252 cairo_fill_preserve (cr);
253 set_source_rgb (cr, fg_colour);
254 cairo_set_line_width (cr, label_border_width ());
257 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
259 /* only plot the name if the bundle has more than one channel;
260 the name of a single channel is assumed to be redundant */
262 cairo_text_extents_t ext;
263 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
264 double const off = (grid_spacing() - ext.height) / 2;
266 Gdk::Color textcolor;
267 ARDOUR_UI_UTILS::set_color_from_rgba(textcolor, ArdourCanvas::contrasting_text_color(ARDOUR_UI_UTILS::gdk_color_to_rgba(bg_colour)));
268 set_source_rgb (cr, textcolor);
269 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
270 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
275 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
281 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
283 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
287 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
291 if (_matrix->show_only_bundles()) {
292 _body->queue_draw_area (
293 component_to_parent_x (bundle_name_x()) - 1,
294 component_to_parent_y (channel_y (bc)) - 1,
295 _longest_bundle_name + name_pad() * 2 + 2,
299 _body->queue_draw_area (
300 component_to_parent_x (port_name_x()) - 1,
301 component_to_parent_y (channel_y (bc)) - 1,
302 _longest_port_name + name_pad() * 2 + 2,
311 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
313 list<PortMatrixNode> const m = _body->mouseover ();
314 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
316 ARDOUR::BundleChannel c = i->column;
317 ARDOUR::BundleChannel r = i->row;
319 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
320 add_channel_highlight (r);
321 } else if (r.bundle) {
322 _body->highlight_associated_channels (_matrix->row_index(), r);
328 PortMatrixRowLabels::motion (double x, double y)
330 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
332 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
339 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
340 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
344 /* if the mouse is over a bundle name, highlight all channels in the bundle */
346 list<PortMatrixNode> n;
348 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
349 if (!_matrix->should_show (w.bundle->channel_type (i))) {
353 ARDOUR::BundleChannel const bc (w.bundle, i);
354 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
357 _body->set_mouseover (n);
360 } else if (x < _width) {
362 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
370 /* not over any bundle */
371 _body->set_mouseover (PortMatrixNode ());