replace use of gdk_pixmap_unref() with g_object_unref
[ardour2.git] / gtk2_ardour / port_matrix_column_labels.cc
blob339767f27dbad33e63aeda70d41586c6f2776545
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 (); ++k) {
67 cairo_text_extents (
68 cr,
69 (*j)->bundle->channel_name (k).c_str(),
70 &ext
73 if (ext.width > _longest_channel_name) {
74 _longest_channel_name = ext.width;
80 /* height metrics */
81 cairo_text_extents_t ext;
82 cairo_text_extents (cr, X_("AQRjpy"), &ext);
83 _text_height = ext.height;
84 _descender_height = ext.height + ext.y_bearing;
86 /* width of the whole thing */
87 if (_matrix->visible_columns()) {
88 _width = group_size (_matrix->visible_columns()) * grid_spacing ();
89 } else {
90 _width = 0;
93 cairo_destroy (cr);
94 g_object_unref (pm);
96 /* height of the whole thing */
98 int a = _longest_bundle_name + 4 * name_pad();
99 if (!_matrix->show_only_bundles()) {
100 a += _longest_channel_name;
103 _height = a * sin (angle()) + _text_height * cos (angle());
104 _overhang = _height / tan (angle ());
105 _width += _overhang;
108 double
109 PortMatrixColumnLabels::basic_text_x_pos (int) const
111 return grid_spacing() / 2 +
112 _text_height / (2 * sin (angle ()));
115 void
116 PortMatrixColumnLabels::render (cairo_t* cr)
118 /* BACKGROUND */
120 set_source_rgb (cr, background_colour());
121 cairo_rectangle (cr, 0, 0, _width, _height);
122 cairo_fill (cr);
124 /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
126 double x = 0;
127 int N = 0;
129 PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
130 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
132 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
133 render_bundle_name (cr, background_colour (), c, x, 0, (*i)->bundle);
135 if (_matrix->show_only_bundles()) {
136 x += grid_spacing();
137 } else {
138 x += (*i)->bundle->nchannels () * grid_spacing();
141 ++N;
144 /* PORT NAMES */
146 if (!_matrix->show_only_bundles()) {
147 x = 0;
148 N = 0;
150 for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
152 for (uint32_t j = 0; j < (*i)->bundle->nchannels(); ++j) {
153 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
154 render_channel_name (cr, background_colour (), c, x, 0, ARDOUR::BundleChannel ((*i)->bundle, j));
155 x += grid_spacing();
158 ++N;
163 double
164 PortMatrixColumnLabels::component_to_parent_x (double x) const
166 return x - _body->xoffset() + _parent_rectangle.get_x();
169 double
170 PortMatrixColumnLabels::parent_to_component_x (double x) const
172 return x + _body->xoffset() - _parent_rectangle.get_x();
175 double
176 PortMatrixColumnLabels::component_to_parent_y (double y) const
178 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
179 return y + _parent_rectangle.get_y();
182 double
183 PortMatrixColumnLabels::parent_to_component_y (double y) const
185 /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
186 return y - _parent_rectangle.get_y();
189 void
190 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
192 list<PortMatrixNode> const m = _body->mouseover ();
193 for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
195 ARDOUR::BundleChannel c = i->column;
196 ARDOUR::BundleChannel r = i->row;
198 if (c.bundle && r.bundle) {
199 add_channel_highlight (c);
200 } else if (c.bundle) {
201 _body->highlight_associated_channels (_matrix->column_index(), c);
206 vector<pair<double, double> >
207 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
209 vector<pair<double, double> > shape;
211 double const lc = _longest_channel_name + name_pad();
212 double const w = grid_spacing();
214 if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
216 double x_ = xoff + _height / tan (angle()) + w;
217 double y_ = yoff;
218 shape.push_back (make_pair (x_, y_));
219 x_ -= w;
220 shape.push_back (make_pair (x_, y_));
221 x_ -= lc * cos (angle());
222 y_ += lc * sin (angle());
223 shape.push_back (make_pair (x_, y_));
224 x_ += w * pow (sin (angle()), 2);
225 y_ += w * sin (angle()) * cos (angle());
226 shape.push_back (make_pair (x_, y_));
228 } else {
230 double x_ = xoff;
231 double y_ = yoff + _height;
232 shape.push_back (make_pair (x_, y_));
233 x_ += w;
234 shape.push_back (make_pair (x_, y_));
235 x_ += lc * cos (angle());
236 y_ -= lc * sin (angle());
237 shape.push_back (make_pair (x_, y_));
238 x_ -= grid_spacing() * pow (sin (angle()), 2);
239 y_ -= grid_spacing() * sin (angle()) * cos (angle());
240 shape.push_back (make_pair (x_, y_));
243 return shape;
246 void
247 PortMatrixColumnLabels::render_bundle_name (
248 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
251 set_source_rgb (cr, bg_colour);
253 double w = 0;
254 if (_matrix->show_only_bundles()) {
255 w = grid_spacing ();
256 } else {
257 w = b->nchannels() * grid_spacing();
260 double x_ = xoff;
262 uint32_t y = yoff;
263 y += _height;
265 double y_ = y;
266 cairo_move_to (cr, x_, y_);
267 x_ += w;
268 cairo_line_to (cr, x_, y_);
269 x_ += _height / tan (angle ());
270 y_ -= _height;
271 cairo_line_to (cr, x_, y_);
272 x_ -= w;
273 cairo_line_to (cr, x_, y_);
274 cairo_line_to (cr, xoff, y);
275 cairo_fill_preserve (cr);
276 set_source_rgb (cr, fg_colour);
277 cairo_set_line_width (cr, label_border_width());
278 cairo_stroke (cr);
280 set_source_rgb (cr, text_colour());
282 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
284 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
286 double rl = 0;
287 if (_matrix->show_only_bundles()) {
288 rl = name_pad();
289 } else {
290 rl = 3 * name_pad() + _longest_channel_name;
292 cairo_move_to (
294 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
295 yoff + _height - q * cos (angle ()) - rl * sin (angle())
298 } else {
300 cairo_move_to (
302 xoff + grid_spacing() - q * sin (angle ()),
303 yoff + _height - q * cos (angle ())
307 cairo_save (cr);
308 cairo_rotate (cr, -angle());
309 cairo_show_text (cr, b->name().c_str());
310 cairo_restore (cr);
313 void
314 PortMatrixColumnLabels::render_channel_name (
315 cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
318 vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
320 cairo_move_to (cr, shape[0].first, shape[0].second);
321 for (uint32_t i = 1; i < 4; ++i) {
322 cairo_line_to (cr, shape[i].first, shape[i].second);
324 cairo_line_to (cr, shape[0].first, shape[0].second);
326 set_source_rgb (cr, bg_colour);
327 cairo_fill_preserve (cr);
328 set_source_rgb (cr, fg_colour);
329 cairo_set_line_width (cr, label_border_width());
330 cairo_stroke (cr);
332 set_source_rgb (cr, text_colour());
334 double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
336 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
338 cairo_move_to (
340 xoff + grid_spacing() - q * sin (angle ()),
341 yoff + _height - q * cos (angle ())
345 } else {
347 double const rl = 3 * name_pad() + _longest_bundle_name;
348 cairo_move_to (
350 xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
351 yoff + _height - q * cos (angle ()) - rl * sin (angle())
355 if (bc.bundle->nchannels() > 1) {
357 /* only plot the name if the bundle has more than one channel;
358 the name of a single channel is assumed to be redundant */
360 cairo_save (cr);
361 cairo_rotate (cr, -angle());
363 cairo_show_text (
365 bc.bundle->channel_name(bc.channel).c_str()
368 cairo_restore (cr);
372 double
373 PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const
375 return channel_to_position (bc, _matrix->visible_columns()) * grid_spacing ();
378 double
379 PortMatrixColumnLabels::channel_y (ARDOUR::BundleChannel const &) const
381 return 0;
384 void
385 PortMatrixColumnLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
387 if (!bc.bundle) {
388 return;
391 if (_matrix->show_only_bundles()) {
393 _body->queue_draw_area (
394 component_to_parent_x (channel_x (bc)) - 1,
395 component_to_parent_y (0) - 1,
396 grid_spacing() + _height * tan (angle()) + 2,
397 _height + 2
400 } else {
402 double const x = channel_x (bc);
403 double const lc = _longest_channel_name + name_pad();
404 double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
406 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
408 _body->queue_draw_area (
409 component_to_parent_x (x) - 1,
410 component_to_parent_y (_height - h) - 1,
411 grid_spacing() + lc * cos (angle()) + 2,
412 h + 2
415 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
417 double const x_ = x + _height / tan (angle()) - lc * cos (angle());
419 _body->queue_draw_area (
420 component_to_parent_x (x_) - 1,
421 component_to_parent_y (0) - 1,
422 grid_spacing() + lc * cos (angle()) + 2,
423 h + 2
431 ARDOUR::BundleChannel
432 PortMatrixColumnLabels::position_to_channel (double p, double o, boost::shared_ptr<const PortGroup> group) const
434 uint32_t const cx = p - (_height - o) * tan (angle ());
435 return PortMatrixComponent::position_to_channel (cx, o, group);
438 void
439 PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t, guint)
441 ARDOUR::BundleChannel w = position_to_channel (x, y, _matrix->visible_columns());
443 if (
444 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > (_height - _longest_bundle_name * sin (angle ()))) ||
445 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_longest_bundle_name * sin (angle ())))
448 w.channel = -1;
451 if (b == 3) {
452 _matrix->popup_menu (
454 ARDOUR::BundleChannel (),
460 void
461 PortMatrixColumnLabels::motion (double x, double y)
463 ARDOUR::BundleChannel const w = position_to_channel (x, y, _matrix->visible_columns());
465 if (w.bundle == 0) {
466 _body->set_mouseover (PortMatrixNode ());
467 return;
470 uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
472 if (
473 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
474 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && y < (_height - bh))
477 /* if the mouse is over a bundle name, highlight all channels in the bundle */
479 list<PortMatrixNode> n;
481 for (uint32_t i = 0; i < w.bundle->nchannels(); ++i) {
482 ARDOUR::BundleChannel const bc (w.bundle, i);
483 n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
486 _body->set_mouseover (n);
488 } else {
490 _body->set_mouseover (PortMatrixNode (ARDOUR::BundleChannel (), w));