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 "gtkmm2ext/colors.h"
27 #include "port_matrix_row_labels.h"
28 #include "port_matrix_column_labels.h"
29 #include "port_matrix.h"
30 #include "port_matrix_body.h"
35 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b, PortMatrixColumnLabels& cols)
36 : PortMatrixLabels (m, b)
37 , _column_labels (cols)
43 PortMatrixRowLabels::compute_dimensions ()
45 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
46 cairo_t* cr = cairo_create (surface);
48 _longest_port_name = 0;
49 _longest_bundle_name = 0;
51 /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
52 we can change between visible groups without the size of the labels jumping around.
55 for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
57 PortGroup::BundleList const r = (*i)->bundles ();
58 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
60 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
62 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
66 cairo_text_extents_t ext;
67 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
68 if (ext.width > _longest_port_name) {
69 _longest_port_name = ext.width;
73 cairo_text_extents_t ext;
74 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
75 if (ext.width > _longest_bundle_name) {
76 _longest_bundle_name = ext.width;
82 if (_matrix->visible_rows()) {
83 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
89 cairo_surface_destroy (surface);
91 _width = _longest_bundle_name +
94 if (!_matrix->show_only_bundles()) {
95 _width += _longest_port_name;
96 _width += name_pad() * 2;
99 uint32_t needed_by_columns = _column_labels.dimensions().second * tan (angle());
101 if (_width < needed_by_columns) {
102 _longest_bundle_name += (needed_by_columns - _width);
103 _width = needed_by_columns;
109 PortMatrixRowLabels::render (cairo_t* cr)
113 set_source_rgb (cr, background_colour());
114 cairo_rectangle (cr, 0, 0, _width, _height);
117 /* BUNDLE AND PORT NAMES */
123 PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
124 for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
125 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
127 if (!_matrix->show_only_bundles()) {
128 uint32_t const N = _matrix->count_of_our_type ((*i)->bundle->nchannels());
129 for (uint32_t j = 0; j < N; ++j) {
130 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
131 ARDOUR::BundleChannel bc (
133 (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
136 render_channel_name (cr, background_colour (), c, 0, y, bc);
142 y += grid_spacing ();
154 PortMatrixRowLabels::button_press (double x, double y, GdkEventButton* ev)
156 ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
159 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
160 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
166 if (Gtkmm2ext::Keyboard::is_delete_event (ev) && w.channel != -1) {
167 _matrix->remove_channel (w);
168 } else if (ev->button == 3) {
169 _matrix->popup_menu (
170 ARDOUR::BundleChannel (),
178 PortMatrixRowLabels::component_to_parent_x (double x) const
180 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
181 return x + _parent_rectangle.get_x();
185 PortMatrixRowLabels::parent_to_component_x (double x) const
187 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
188 return x - _parent_rectangle.get_x();
192 PortMatrixRowLabels::component_to_parent_y (double y) const
194 return y - _body->yoffset() + _parent_rectangle.get_y();
198 PortMatrixRowLabels::parent_to_component_y (double y) const
200 return y + _body->yoffset() - _parent_rectangle.get_y();
205 PortMatrixRowLabels::bundle_name_x () const
209 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
210 x = _longest_port_name + name_pad() * 2;
217 PortMatrixRowLabels::port_name_x () const
219 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
220 return _longest_bundle_name + name_pad() * 2;
229 PortMatrixRowLabels::render_bundle_name (
230 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
233 double const x = bundle_name_x ();
235 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
236 set_source_rgb (cr, bg_colour);
237 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
238 cairo_fill_preserve (cr);
239 set_source_rgb (cr, fg_colour);
240 cairo_set_line_width (cr, label_border_width ());
243 cairo_text_extents_t ext;
244 cairo_text_extents (cr, b->name().c_str(), &ext);
245 double const off = (grid_spacing() - ext.height) / 2;
247 Gdk::Color textcolor;
248 ARDOUR_UI_UTILS::set_color_from_rgba(textcolor, Gtkmm2ext::contrasting_text_color(ARDOUR_UI_UTILS::gdk_color_to_rgba(bg_colour)));
249 set_source_rgb (cr, textcolor);
250 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
251 cairo_show_text (cr, b->name().c_str());
255 PortMatrixRowLabels::render_channel_name (
256 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
259 set_source_rgb (cr, bg_colour);
260 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
261 cairo_fill_preserve (cr);
262 set_source_rgb (cr, fg_colour);
263 cairo_set_line_width (cr, label_border_width ());
266 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
268 /* only plot the name if the bundle has more than one channel;
269 the name of a single channel is assumed to be redundant */
271 cairo_text_extents_t ext;
272 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
273 double const off = (grid_spacing() - ext.height) / 2;
275 Gdk::Color textcolor;
276 ARDOUR_UI_UTILS::set_color_from_rgba(textcolor, Gtkmm2ext::contrasting_text_color(ARDOUR_UI_UTILS::gdk_color_to_rgba(bg_colour)));
277 set_source_rgb (cr, textcolor);
278 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
279 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
284 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
290 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
292 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
296 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
300 if (_matrix->show_only_bundles()) {
301 _body->queue_draw_area (
302 component_to_parent_x (bundle_name_x()) - 1,
303 component_to_parent_y (channel_y (bc)) - 1,
304 _longest_bundle_name + name_pad() * 2 + 2,
308 _body->queue_draw_area (
309 component_to_parent_x (port_name_x()) - 1,
310 component_to_parent_y (channel_y (bc)) - 1,
311 _longest_port_name + name_pad() * 2 + 2,
320 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
322 list<PortMatrixNode> const m = _body->mouseover ();
323 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
325 ARDOUR::BundleChannel c = i->column;
326 ARDOUR::BundleChannel r = i->row;
328 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
329 add_channel_highlight (r);
330 } else if (r.bundle) {
331 _body->highlight_associated_channels (_matrix->row_index(), r);
337 PortMatrixRowLabels::motion (double x, double y)
339 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
341 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
348 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
349 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
353 /* if the mouse is over a bundle name, highlight all channels in the bundle */
355 list<PortMatrixNode> n;
357 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
358 if (!_matrix->should_show (w.bundle->channel_type (i))) {
362 ARDOUR::BundleChannel const bc (w.bundle, i);
363 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
366 _body->set_mouseover (n);
369 } else if (x < _width) {
371 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
379 /* not over any bundle */
380 _body->set_mouseover (PortMatrixNode ());