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"
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, GdkEventButton* ev)
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))
155 if (Gtkmm2ext::Keyboard::is_delete_event (ev) && w.channel != -1) {
156 _matrix->remove_channel (w);
157 } else if (ev->button == 3) {
158 _matrix->popup_menu (
159 ARDOUR::BundleChannel (),
167 PortMatrixRowLabels::component_to_parent_x (double x) const
169 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
170 return x + _parent_rectangle.get_x();
174 PortMatrixRowLabels::parent_to_component_x (double x) const
176 /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
177 return x - _parent_rectangle.get_x();
181 PortMatrixRowLabels::component_to_parent_y (double y) const
183 return y - _body->yoffset() + _parent_rectangle.get_y();
187 PortMatrixRowLabels::parent_to_component_y (double y) const
189 return y + _body->yoffset() - _parent_rectangle.get_y();
194 PortMatrixRowLabels::bundle_name_x () const
198 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
199 x = _longest_port_name + name_pad() * 2;
206 PortMatrixRowLabels::port_name_x () const
208 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
209 return _longest_bundle_name + name_pad() * 2;
218 PortMatrixRowLabels::render_bundle_name (
219 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
222 double const x = bundle_name_x ();
224 int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type_min_1 (b->nchannels());
225 set_source_rgb (cr, bg_colour);
226 cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
227 cairo_fill_preserve (cr);
228 set_source_rgb (cr, fg_colour);
229 cairo_set_line_width (cr, label_border_width ());
232 cairo_text_extents_t ext;
233 cairo_text_extents (cr, b->name().c_str(), &ext);
234 double const off = (grid_spacing() - ext.height) / 2;
236 set_source_rgb (cr, text_colour());
237 cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
238 cairo_show_text (cr, b->name().c_str());
242 PortMatrixRowLabels::render_channel_name (
243 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
246 set_source_rgb (cr, bg_colour);
247 cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
248 cairo_fill_preserve (cr);
249 set_source_rgb (cr, fg_colour);
250 cairo_set_line_width (cr, label_border_width ());
253 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
255 /* only plot the name if the bundle has more than one channel;
256 the name of a single channel is assumed to be redundant */
258 cairo_text_extents_t ext;
259 cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
260 double const off = (grid_spacing() - ext.height) / 2;
262 set_source_rgb (cr, text_colour());
263 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
264 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
269 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
275 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
277 return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
281 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
285 if (_matrix->show_only_bundles()) {
286 _body->queue_draw_area (
287 component_to_parent_x (bundle_name_x()) - 1,
288 component_to_parent_y (channel_y (bc)) - 1,
289 _longest_bundle_name + name_pad() * 2 + 2,
293 _body->queue_draw_area (
294 component_to_parent_x (port_name_x()) - 1,
295 component_to_parent_y (channel_y (bc)) - 1,
296 _longest_port_name + name_pad() * 2 + 2,
305 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
307 list<PortMatrixNode> const m = _body->mouseover ();
308 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
310 ARDOUR::BundleChannel c = i->column;
311 ARDOUR::BundleChannel r = i->row;
313 if (PortMatrix::bundle_with_channels (c.bundle) && PortMatrix::bundle_with_channels (r.bundle)) {
314 add_channel_highlight (r);
315 } else if (r.bundle) {
316 _body->highlight_associated_channels (_matrix->row_index(), r);
322 PortMatrixRowLabels::motion (double x, double y)
324 ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
326 uint32_t const bw = _longest_bundle_name + 2 * name_pad();
333 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
334 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
338 /* if the mouse is over a bundle name, highlight all channels in the bundle */
340 list<PortMatrixNode> n;
342 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
343 if (!_matrix->should_show (w.bundle->channel_type (i))) {
347 ARDOUR::BundleChannel const bc (w.bundle, i);
348 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
351 _body->set_mouseover (n);
354 } else if (x < _width) {
356 _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
364 /* not over any bundle */
365 _body->set_mouseover (PortMatrixNode ());