Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / gtk2_ardour / port_matrix_column_labels.cc
blobac4e1fef45236355ab4ef23b3a3bfb63c60e965b
1 /*
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.
20 #include <iostream>
21 #include "ardour/bundle.h"
22 #include "ardour/types.h"
23 #include "port_matrix_column_labels.h"
24 #include "port_matrix.h"
25 #include "port_matrix_body.h"
26 #include "utils.h"
28 #include "i18n.h"
30 using namespace std;
32 PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrix* m, PortMatrixBody* b)
33 : PortMatrixLabels (m, b),
34 _overhang (0)
39 void
40 PortMatrixColumnLabels::compute_dimensions ()
42 GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
43 gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
44 cairo_t* cr = gdk_cairo_create (pm);
46 /* width of the longest bundle name */
47 _longest_bundle_name = 0;
48 /* width of the longest channel name */
49 _longest_channel_name = 0;
51 /* Compute 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->columns()->begin(); i != _matrix->columns()->end(); ++i) {
56 PortGroup::BundleList const c = _matrix->columns()->bundles();
57 for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
59 cairo_text_extents_t ext;
60 cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
61 if (ext.width > _longest_bundle_name) {
62 _longest_bundle_name = ext.width;
65 for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
67 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
68 continue;
71 cairo_text_extents (
72 cr,
73 (*j)->bundle->channel_name (k).c_str(),
74 &ext
77 if (ext.width > _longest_channel_name) {
78 _longest_channel_name = ext.width;
84 /* height metrics */
85 cairo_text_extents_t ext;
86 cairo_text_extents (cr, X_("AQRjpy"), &ext);
87 _text_height = ext.height;
88 _descender_height = ext.height + ext.y_bearing;
90 /* width of the whole thing */
91 if (_matrix->visible_columns()) {
92 _width = group_size (_matrix->visible_columns()) * grid_spacing ();
93 } else {
94 _width = 0;
97 cairo_destroy (cr);
98 g_object_unref (pm);
100 /* height of the whole thing */
102 int a = _longest_bundle_name + 4 * name_pad();
103 if (!_matrix->show_only_bundles()) {
104 a += _longest_channel_name;
107 _height = a * sin (angle()) + _text_height * cos (angle());
108 _overhang = _height / tan (angle ());
109 _width += _overhang;
112 double
113 PortMatrixColumnLabels::basic_text_x_pos (int) const
115 return grid_spacing() / 2 +
116 _text_height / (2 * sin (angle ()));
119 void
120 PortMatrixColumnLabels::render (cairo_t* cr)
122 /* BACKGROUND */
124 set_source_rgb (cr, background_colour());
125 cairo_rectangle (cr, 0, 0, _width, _height);
126 cairo_fill (cr);
128 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
130 double x = 0;
131 int N = 0;
133 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
134 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
136 bool should_show_this_bundle = false;
137 for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
138 if (_matrix->should_show ((*i)->bundle->channel_type (j))) {
139 should_show_this_bundle = true;
140 break;
144 if (should_show_this_bundle) {
145 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
146 render_bundle_name (cr, background_colour (), c, x, 0, (*i)->bundle);
149 if (_matrix->show_only_bundles()) {
150 x += grid_spacing();
151 } else {
152 x += _matrix->count_of_our_type ((*i)->bundle->nchannels()) * grid_spacing();
155 ++N;
158 /* PORT NAMES */
160 if (!_matrix->show_only_bundles()) {
161 x = 0;
162 N = 0;
164 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
166 for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
168 if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
169 continue;
172 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
173 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel ((*i)->bundle, j));
174 x += grid_spacing();
177 ++N;
182 double
183 PortMatrixColumnLabels::component_to_parent_x (double x) const
185 return x - _body->xoffset() + _parent_rectangle.get_x();
188 double
189 PortMatrixColumnLabels::parent_to_component_x (double x) const
191 return x + _body->xoffset() - _parent_rectangle.get_x();
194 double
195 PortMatrixColumnLabels::component_to_parent_y (double y) const
197 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
198 return y + _parent_rectangle.get_y();
201 double
202 PortMatrixColumnLabels::parent_to_component_y (double y) const
204 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
205 return y - _parent_rectangle.get_y();
208 void
209 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
211 list<PortMatrixNode> const m = _body->mouseover ();
212 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
214 ARDOUR::BundleChannel c = i->column;
215 ARDOUR::BundleChannel r = i->row;
217 if (c.bundle && r.bundle) {
218 add_channel_highlight (c);
219 } else if (c.bundle) {
220 _body->highlight_associated_channels (_matrix->column_index(), c);
225 vector<pair<double, double> >
226 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
228 vector<pair<double, double> > shape;
230 double const lc = _longest_channel_name + name_pad();
231 double const w = grid_spacing();
233 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
235 double x_ = xoff + _height / tan (angle()) + w;
236 double y_ = yoff;
237 shape.push_back (make_pair (x_, y_));
238 x_ -= w;
239 shape.push_back (make_pair (x_, y_));
240 x_ -= lc * cos (angle());
241 y_ += lc * sin (angle());
242 shape.push_back (make_pair (x_, y_));
243 x_ += w * pow (sin (angle()), 2);
244 y_ += w * sin (angle()) * cos (angle());
245 shape.push_back (make_pair (x_, y_));
247 } else {
249 double x_ = xoff;
250 double y_ = yoff + _height;
251 shape.push_back (make_pair (x_, y_));
252 x_ += w;
253 shape.push_back (make_pair (x_, y_));
254 x_ += lc * cos (angle());
255 y_ -= lc * sin (angle());
256 shape.push_back (make_pair (x_, y_));
257 x_ -= grid_spacing() * pow (sin (angle()), 2);
258 y_ -= grid_spacing() * sin (angle()) * cos (angle());
259 shape.push_back (make_pair (x_, y_));
262 return shape;
265 void
266 PortMatrixColumnLabels::render_bundle_name (
267 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
270 set_source_rgb (cr, bg_colour);
272 double w = 0;
273 if (_matrix->show_only_bundles()) {
274 w = grid_spacing ();
275 } else {
276 w = _matrix->count_of_our_type (b->nchannels()) * grid_spacing();
279 double x_ = xoff;
281 uint32_t y = yoff;
282 y += _height;
284 double y_ = y;
285 cairo_move_to (cr, x_, y_);
286 x_ += w;
287 cairo_line_to (cr, x_, y_);
288 x_ += _height / tan (angle ());
289 y_ -= _height;
290 cairo_line_to (cr, x_, y_);
291 x_ -= w;
292 cairo_line_to (cr, x_, y_);
293 cairo_line_to (cr, xoff, y);
294 cairo_fill_preserve (cr);
295 set_source_rgb (cr, fg_colour);
296 cairo_set_line_width (cr, label_border_width());
297 cairo_stroke (cr);
299 set_source_rgb (cr, text_colour());
301 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
303 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
305 double rl = 0;
306 if (_matrix->show_only_bundles()) {
307 rl = name_pad();
308 } else {
309 rl = 3 * name_pad() + _longest_channel_name;
311 cairo_move_to (
313 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
314 yoff + _height - q * cos (angle ()) - rl * sin (angle())
317 } else {
319 cairo_move_to (
321 xoff + grid_spacing() - q * sin (angle ()),
322 yoff + _height - q * cos (angle ())
326 cairo_save (cr);
327 cairo_rotate (cr, -angle());
328 cairo_show_text (cr, b->name().c_str());
329 cairo_restore (cr);
332 void
333 PortMatrixColumnLabels::render_channel_name (
334 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
337 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
339 cairo_move_to (cr, shape[0].first, shape[0].second);
340 for (uint32_t i = 1; i < 4; ++i) {
341 cairo_line_to (cr, shape[i].first, shape[i].second);
343 cairo_line_to (cr, shape[0].first, shape[0].second);
345 set_source_rgb (cr, bg_colour);
346 cairo_fill_preserve (cr);
347 set_source_rgb (cr, fg_colour);
348 cairo_set_line_width (cr, label_border_width());
349 cairo_stroke (cr);
351 set_source_rgb (cr, text_colour());
353 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
355 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
357 cairo_move_to (
359 xoff + grid_spacing() - q * sin (angle ()),
360 yoff + _height - q * cos (angle ())
364 } else {
366 double const rl = 3 * name_pad() + _longest_bundle_name;
367 cairo_move_to (
369 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
370 yoff + _height - q * cos (angle ()) - rl * sin (angle())
374 if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
376 /* only plot the name if the bundle has more than one channel;
377 the name of a single channel is assumed to be redundant */
379 cairo_save (cr);
380 cairo_rotate (cr, -angle());
382 cairo_show_text (
384 bc.bundle->channel_name(bc.channel).c_str()
387 cairo_restore (cr);
391 double
392 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
394 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
397 double
398 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
400 return 0;
403 void
404 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
406 if (!bc.bundle) {
407 return;
410 if (_matrix->show_only_bundles()) {
412 _body->queue_draw_area (
413 component_to_parent_x (channel_x (bc)) - 1,
414 component_to_parent_y (0) - 1,
415 grid_spacing() + _height * tan (angle()) + 2,
416 _height + 2
419 } else {
421 double const x = channel_x (bc);
422 double const lc = _longest_channel_name + name_pad();
423 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
425 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
427 _body->queue_draw_area (
428 component_to_parent_x (x) - 1,
429 component_to_parent_y (_height - h) - 1,
430 grid_spacing() + lc * cos (angle()) + 2,
431 h + 2
434 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
436 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
438 _body->queue_draw_area (
439 component_to_parent_x (x_) - 1,
440 component_to_parent_y (0) - 1,
441 grid_spacing() + lc * cos (angle()) + 2,
442 h + 2
450 ARDOUR::BundleChannel
451 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
453 uint32_t const cx = p - (_height - o) * tan (angle ());
454 return PortMatrixComponent::position_to_channel (cx, o, group);
457 void
458 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
460 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
462 if (
463 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
464 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
467 w.channel = -1;
470 if (b == 3) {
471 _matrix->popup_menu (
473 ARDOUR::BundleChannel (),
479 void
480 PortMatrixColumnLabels::motion (double x, double y)
482 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
484 if (w.bundle == 0) {
485 _body->set_mouseover (PortMatrixNode ());
486 return;
489 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
491 if (
492 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
493 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
496 /* if the mouse is over a bundle name, highlight all channels in the bundle */
498 list<PortMatrixNode> n;
500 for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
502 if (!_matrix->should_show (w.bundle->channel_type(i))) {
503 continue;
506 ARDOUR::BundleChannel const bc (w.bundle, i);
507 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
510 _body->set_mouseover (n);
512 } else {
514 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));