ardour
port_matrix_column_labels.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2009 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #include <iostream>
21 #include "gtkmm2ext/keyboard.h"
22 #include "ardour/bundle.h"
23 #include "canvas/colors.h"
24 #include "utils.h"
26 #include "port_matrix.h"
27 #include "port_matrix_body.h"
28 
29 #include "i18n.h"
30 
31 using namespace std;
32 
34  : PortMatrixLabels (m, b),
35  _overhang (0)
36 {
37 
38 }
39 
40 void
42 {
43  cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 200);
44  cairo_t* cr = cairo_create (surface);
45 
46  /* width of the longest bundle name */
48  /* width of the longest channel name */
50 
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.
53  */
54 
55  for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) {
57  for (PortGroup::BundleList::const_iterator j = c.begin (); j != c.end(); ++j) {
58 
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;
63  }
64 
65  for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
66 
67  if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
68  continue;
69  }
70 
71  cairo_text_extents (
72  cr,
73  (*j)->bundle->channel_name (k).c_str(),
74  &ext
75  );
76 
77  if (ext.width > _longest_channel_name) {
78  _longest_channel_name = ext.width;
79  }
80  }
81  }
82  }
83 
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;
89 
90  /* width of the whole thing */
91  if (_matrix->visible_columns()) {
93  } else {
94  _width = 0;
95  }
96 
97  cairo_destroy (cr);
98  cairo_surface_destroy (surface);
99 
100  /* height of the whole thing */
101 
102  int a = _longest_bundle_name + 4 * name_pad();
103  if (!_matrix->show_only_bundles()) {
105  }
106 
107  _height = a * sin (angle()) + _text_height * cos (angle());
108  _overhang = _height / tan (angle ());
109  _width += _overhang;
110 }
111 
112 double
114 {
115  return grid_spacing() / 2 +
116  _text_height / (2 * sin (angle ()));
117 }
118 
119 void
121 {
122  /* BACKGROUND */
123 
125  cairo_rectangle (cr, 0, 0, _width, _height);
126  cairo_fill (cr);
127 
128  /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
129 
130  double x = 0;
131  int N = 0;
132 
133  PortGroup::BundleList const & bundles = _matrix->visible_columns()->bundles ();
134  for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
135 
136  Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
137  render_bundle_name (cr, background_colour (), c, x, 0, (*i)->bundle);
138 
139  if (_matrix->show_only_bundles()) {
140  x += grid_spacing();
141  } else {
142  x += _matrix->count_of_our_type_min_1 ((*i)->bundle->nchannels()) * grid_spacing();
143  }
144 
145  ++N;
146  }
147 
148  /* PORT NAMES */
149 
150  if (!_matrix->show_only_bundles()) {
151  x = 0;
152  N = 0;
153 
154  for (PortGroup::BundleList::const_iterator i = bundles.begin (); i != bundles.end(); ++i) {
155 
156  uint32_t const C = _matrix->count_of_our_type ((*i)->bundle->nchannels ());
157 
158  for (uint32_t j = 0; j < C; ++j) {
159  Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N);
160 
162  (*i)->bundle,
163  (*i)->bundle->type_channel_to_overall (_matrix->type (), j)
164  );
165 
166  render_channel_name (cr, background_colour (), c, x, 0, bc);
167  x += grid_spacing();
168  }
169 
170  if (C == 0) {
171  x += grid_spacing ();
172  }
173 
174  ++N;
175  }
176  }
177 }
178 
179 double
181 {
182  return x - _body->xoffset() + _parent_rectangle.get_x();
183 }
184 
185 double
187 {
188  return x + _body->xoffset() - _parent_rectangle.get_x();
189 }
190 
191 double
193 {
194  /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
195  return y + _parent_rectangle.get_y();
196 }
197 
198 double
200 {
201  /* Column labels don't scroll vertically, so y conversion does not depend on yoffset */
202  return y - _parent_rectangle.get_y();
203 }
204 
205 void
206 PortMatrixColumnLabels::mouseover_changed (list<PortMatrixNode> const &)
207 {
208  list<PortMatrixNode> const m = _body->mouseover ();
209  for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
210 
211  ARDOUR::BundleChannel c = i->column;
212  ARDOUR::BundleChannel r = i->row;
213 
216  } else if (c.bundle) {
218  }
219  }
220 }
221 
222 vector<pair<double, double> >
223 PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const
224 {
225  vector<pair<double, double> > shape;
226 
227  double const lc = _longest_channel_name + name_pad();
228  double const w = grid_spacing();
229 
231 
232  double x_ = xoff + _height / tan (angle()) + w;
233  double y_ = yoff;
234  shape.push_back (make_pair (x_, y_));
235  x_ -= w;
236  shape.push_back (make_pair (x_, y_));
237  x_ -= lc * cos (angle());
238  y_ += lc * sin (angle());
239  shape.push_back (make_pair (x_, y_));
240  x_ += w * pow (sin (angle()), 2);
241  y_ += w * sin (angle()) * cos (angle());
242  shape.push_back (make_pair (x_, y_));
243 
244  } else {
245 
246  double x_ = xoff;
247  double y_ = yoff + _height;
248  shape.push_back (make_pair (x_, y_));
249  x_ += w;
250  shape.push_back (make_pair (x_, y_));
251  x_ += lc * cos (angle());
252  y_ -= lc * sin (angle());
253  shape.push_back (make_pair (x_, y_));
254  x_ -= grid_spacing() * pow (sin (angle()), 2);
255  y_ -= grid_spacing() * sin (angle()) * cos (angle());
256  shape.push_back (make_pair (x_, y_));
257  }
258 
259  return shape;
260 }
261 
262 void
264  cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
265  )
266 {
267  set_source_rgb (cr, bg_colour);
268 
269  double w = 0;
270  if (_matrix->show_only_bundles()) {
271  w = grid_spacing ();
272  } else {
274  }
275 
276  double x_ = xoff;
277 
278  uint32_t y = yoff;
279  y += _height;
280 
281  double y_ = y;
282  cairo_move_to (cr, x_, y_);
283  x_ += w;
284  cairo_line_to (cr, x_, y_);
285  x_ += _height / tan (angle ());
286  y_ -= _height;
287  cairo_line_to (cr, x_, y_);
288  x_ -= w;
289  cairo_line_to (cr, x_, y_);
290  cairo_line_to (cr, xoff, y);
291  cairo_fill_preserve (cr);
292  set_source_rgb (cr, fg_colour);
293  cairo_set_line_width (cr, label_border_width());
294  cairo_stroke (cr);
295 
296  Gdk::Color textcolor;
298  set_source_rgb (cr, textcolor);
299 
300  double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
301 
303 
304  double rl = 0;
305  if (_matrix->show_only_bundles()) {
306  rl = name_pad();
307  } else {
308  rl = 3 * name_pad() + _longest_channel_name;
309  }
310  cairo_move_to (
311  cr,
312  xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle()),
313  yoff + _height - q * cos (angle ()) - rl * sin (angle())
314  );
315 
316  } else {
317 
318  cairo_move_to (
319  cr,
320  xoff + grid_spacing() - q * sin (angle ()),
321  yoff + _height - q * cos (angle ())
322  );
323  }
324 
325  cairo_save (cr);
326  cairo_rotate (cr, -angle());
327  cairo_show_text (cr, b->name().c_str());
328  cairo_restore (cr);
329 }
330 
331 void
333  cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc
334  )
335 {
336  vector<pair<double, double> > const shape = port_name_shape (xoff, yoff);
337 
338  cairo_move_to (cr, shape[0].first, shape[0].second);
339  for (uint32_t i = 1; i < 4; ++i) {
340  cairo_line_to (cr, shape[i].first, shape[i].second);
341  }
342  cairo_line_to (cr, shape[0].first, shape[0].second);
343 
344  set_source_rgb (cr, bg_colour);
345  cairo_fill_preserve (cr);
346  set_source_rgb (cr, fg_colour);
347  cairo_set_line_width (cr, label_border_width());
348  cairo_stroke (cr);
349 
350  Gdk::Color textcolor;
352  set_source_rgb (cr, textcolor);
353 
354  double const q = ((grid_spacing() * sin (angle())) - _text_height) / 2 + _descender_height;
355 
357 
358  cairo_move_to (
359  cr,
360  xoff + grid_spacing() - q * sin (angle ()),
361  yoff + _height - q * cos (angle ())
362  );
363 
364 
365  } else {
366 
367  double const rl = 3 * name_pad() + _longest_bundle_name;
368  cairo_move_to (
369  cr,
370  xoff + grid_spacing() - q * sin (angle ()) + rl * cos (angle ()),
371  yoff + _height - q * cos (angle ()) - rl * sin (angle())
372  );
373  }
374 
375  if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
376 
377  /* only plot the name if the bundle has more than one channel;
378  the name of a single channel is assumed to be redundant */
379 
380  cairo_save (cr);
381  cairo_rotate (cr, -angle());
382 
383  cairo_show_text (
384  cr,
385  bc.bundle->channel_name(bc.channel).c_str()
386  );
387 
388  cairo_restore (cr);
389  }
390 }
391 
392 double
394 {
396 }
397 
398 double
400 {
401  return 0;
402 }
403 
404 void
406 {
407  if (!bc.bundle) {
408  return;
409  }
410 
411  if (_matrix->show_only_bundles()) {
412 
413  _body->queue_draw_area (
414  component_to_parent_x (channel_x (bc)) - 1,
415  component_to_parent_y (0) - 1,
416  grid_spacing() + _height * tan (angle()) + 2,
417  _height + 2
418  );
419 
420  } else {
421 
422  double const x = channel_x (bc);
423  double const lc = _longest_channel_name + name_pad();
424  double const h = lc * sin (angle ()) + grid_spacing() * sin (angle()) * cos (angle());
425 
427 
428  _body->queue_draw_area (
429  component_to_parent_x (x) - 1,
430  component_to_parent_y (_height - h) - 1,
431  grid_spacing() + lc * cos (angle()) + 2,
432  h + 2
433  );
434 
436 
437  double const x_ = x + _height / tan (angle()) - lc * cos (angle());
438 
439  _body->queue_draw_area (
440  component_to_parent_x (x_) - 1,
441  component_to_parent_y (0) - 1,
442  grid_spacing() + lc * cos (angle()) + 2,
443  h + 2
444  );
445 
446  }
447 
448  }
449 }
450 
453 {
454  uint32_t const cx = p - (_height - o) * tan (angle ());
455  return PortMatrixComponent::position_to_channel (cx, o, group);
456 }
457 
458 void
459 PortMatrixColumnLabels::button_press (double x, double y, GdkEventButton* ev)
460 {
462 
463  if (
466  ) {
467 
468  w.channel = -1;
469  }
470 
471  if (Gtkmm2ext::Keyboard::is_delete_event (ev) && w.channel != -1) {
472  _matrix->remove_channel (w);
473  } else if (ev->button == 3) {
475  w,
477  ev->time
478  );
479  }
480 }
481 
482 void
483 PortMatrixColumnLabels::motion (double x, double y)
484 {
486 
487  if (w.bundle == 0) {
489  return;
490  }
491 
492  uint32_t const bh = _longest_channel_name * sin (angle ()) + _text_height / cos (angle ());
493 
494  if (
495  (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && y > bh) ||
497  ) {
498 
499  /* if the mouse is over a bundle name, highlight all channels in the bundle */
500 
501  list<PortMatrixNode> n;
502 
503  for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
504  if (!_matrix->should_show (w.bundle->channel_type (i))) {
505  continue;
506  }
507 
508  ARDOUR::BundleChannel const bc (w.bundle, i);
509  n.push_back (PortMatrixNode (ARDOUR::BundleChannel (), bc));
510  }
511 
512  _body->set_mouseover (n);
513 
514  } else {
515 
517  }
518 }
void popup_menu(ARDOUR::BundleChannel, ARDOUR::BundleChannel, uint32_t)
Definition: port_matrix.cc:418
void add_channel_highlight(ARDOUR::BundleChannel const &)
double parent_to_component_x(double x) const
std::vector< std::pair< double, double > > port_name_shape(double, double) const
void set_source_rgb(cairo_t *, Gdk::Color const &)
List::const_iterator begin() const
Definition: port_group.h:123
static uint32_t name_pad()
virtual void remove_channel(ARDOUR::BundleChannel)
Definition: port_matrix.cc:747
std::list< BundleRecord * > BundleList
Definition: port_group.h:86
uint32_t xoffset() const
static int N
Definition: signals_test.cc:27
bool should_show(ARDOUR::DataType) const
Definition: Beats.hpp:239
double component_to_parent_x(double x) const
static uint32_t grid_spacing()
std::list< PortMatrixNode > mouseover() const
uint32_t count_of_our_type(ARDOUR::ChanCount) const
static Gdk::Color get_a_bundle_colour(int x)
ARDOUR::BundleChannel position_to_channel(double, double, boost::shared_ptr< const PortGroup >) const
void render_channel_name(cairo_t *, Gdk::Color, Gdk::Color, double, double, ARDOUR::BundleChannel const &)
double channel_x(ARDOUR::BundleChannel const &) const
double component_to_parent_y(double y) const
List::const_iterator end() const
Definition: port_group.h:127
column labels on top, row labels to the right
Definition: port_matrix.h:84
uint32_t _height
full height of the contents
uint32_t gdk_color_to_rgba(Gdk::Color const &)
Definition: utils.cc:285
#define X_(Text)
Definition: i18n.h:13
uint32_t contrasting_text_color(uint32_t c)
void set_color_from_rgba(Gdk::Color &, uint32_t)
Definition: utils.cc:276
uint32_t group_size(boost::shared_ptr< const PortGroup >) const
double parent_to_component_y(double y) const
PortGroup::BundleList const & bundles() const
Definition: port_group.cc:686
virtual ARDOUR::BundleChannel position_to_channel(double, double, boost::shared_ptr< const PortGroup >) const
ChanCount nchannels() const
Definition: bundle.cc:68
uint32_t channel_to_position(ARDOUR::BundleChannel, boost::shared_ptr< const PortGroup >) const
void mouseover_changed(std::list< PortMatrixNode > const &)
uint32_t count_of_our_type_min_1(ARDOUR::ChanCount) const
Gdk::Rectangle _parent_rectangle
std::string name() const
Definition: bundle.h:110
void highlight_associated_channels(int, ARDOUR::BundleChannel)
static uint32_t label_border_width()
PortMatrixBody * _body
the PortMatrixBody that we're in
row labels to the left, column labels on the bottom
Definition: port_matrix.h:85
bool show_only_bundles() const
Definition: port_matrix.h:94
ARDOUR::DataType type() const
Definition: port_matrix.h:68
static bool is_delete_event(GdkEventButton *)
Definition: keyboard.cc:498
void set_mouseover(PortMatrixNode const &)
uint32_t _width
full width of the contents
boost::shared_ptr< Bundle > bundle
Definition: bundle.h:168
void render_bundle_name(cairo_t *, Gdk::Color, Gdk::Color, double, double, boost::shared_ptr< ARDOUR::Bundle >)
double channel_y(ARDOUR::BundleChannel const &) const
void button_press(double, double, GdkEventButton *)
boost::shared_ptr< const PortGroup > visible_columns() const
Definition: port_matrix.cc:396
int channel
channel index, or -1 for "all"
Definition: bundle.h:169
PortMatrixColumnLabels(PortMatrix *, PortMatrixBody *)
static bool bundle_with_channels(boost::shared_ptr< ARDOUR::Bundle >)
Arrangement arrangement() const
Definition: port_matrix.h:90
PortGroupList const * columns() const
Definition: port_matrix.cc:390
void queue_draw_for(ARDOUR::BundleChannel const &)
int column_index() const
Definition: port_matrix.h:102