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 "ardour/bundle.h"
22
#include "ardour/types.h"
24
#include "gui_thread.h"
25
#include "port_matrix_body.h"
26
#include "port_matrix.h"
27
#include "port_matrix_column_labels.h"
28
#include "port_matrix_row_labels.h"
29
#include "port_matrix_grid.h"
35
PortMatrixBody::PortMatrixBody (PortMatrix* p)
41
_column_labels_border_x (0),
42
_column_labels_height (0),
43
_ignore_component_size_changed (false)
45
_column_labels = new PortMatrixColumnLabels (p, this);
46
_row_labels = new PortMatrixRowLabels (p, this);
47
_grid = new PortMatrixGrid (p, this);
49
_components.push_back (_column_labels);
50
_components.push_back (_row_labels);
51
_components.push_back (_grid);
53
add_events (Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK);
57
PortMatrixBody::~PortMatrixBody ()
59
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
65
PortMatrixBody::on_expose_event (GdkEventExpose* event)
68
_matrix->visible_columns() == 0 || _matrix->visible_rows() == 0 ||
69
_matrix->visible_columns()->bundles().empty() || _matrix->visible_rows()->bundles().empty()
72
/* nothing to connect */
74
cairo_t* cr = gdk_cairo_create (get_window()->gobj());
76
cairo_set_source_rgb (cr, 0, 0, 0);
77
cairo_rectangle (cr, 0, 0, _alloc_width, _alloc_height);
81
if (_matrix->type() == ARDOUR::DataType::NIL) {
82
t = _("There are no ports to connect.");
84
t = string_compose (_("There are no %1 ports to connect."), _matrix->type().to_i18n_string());
87
cairo_text_extents_t ext;
88
cairo_text_extents (cr, t.c_str(), &ext);
90
cairo_set_source_rgb (cr, 1, 1, 1);
91
cairo_move_to (cr, (_alloc_width - ext.width) / 2, (_alloc_height + ext.height) / 2);
92
cairo_show_text (cr, t.c_str ());
99
Gdk::Rectangle const exposure (
100
event->area.x, event->area.y, event->area.width, event->area.height
105
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
107
Gdk::Rectangle r = exposure;
109
/* the get_pixmap call may cause things to be rerendered and sizes to change,
110
so fetch the pixmap before calculating where to put it */
111
GdkPixmap* p = (*i)->get_pixmap (get_window()->gobj());
112
r.intersect ((*i)->parent_rectangle(), intersects);
117
get_window()->gobj(),
118
get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
120
(*i)->parent_to_component_x (r.get_x()),
121
(*i)->parent_to_component_y (r.get_y()),
131
cairo_t* cr = gdk_cairo_create (get_window()->gobj());
133
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
135
set_cairo_clip (cr, (*i)->parent_rectangle ());
136
(*i)->draw_extra (cr);
146
PortMatrixBody::on_size_request (Gtk::Requisition *req)
148
pair<int, int> const col = _column_labels->dimensions ();
149
pair<int, int> const row = _row_labels->dimensions ();
150
pair<int, int> const grid = _grid->dimensions ();
152
if (grid.first == 0 && grid.second == 0) {
153
/* nothing to display */
159
/* don't ask for the maximum size of our contents, otherwise GTK won't
160
let the containing window shrink below this size */
162
/* XXX these shouldn't be hard-coded */
163
int const min_width = 512;
164
int const min_height = 512;
166
req->width = min (min_width, max (col.first, grid.first + row.first));
167
req->height = min (min_height / _matrix->min_height_divisor(), col.second + grid.second);
171
PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
173
Gtk::EventBox::on_size_allocate (alloc);
175
_alloc_width = alloc.get_width ();
176
_alloc_height = alloc.get_height ();
178
compute_rectangles ();
179
_matrix->setup_scrollbars ();
183
PortMatrixBody::compute_rectangles ()
185
/* full sizes of components */
186
pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
187
uint32_t const col_overhang = _column_labels->overhang ();
188
pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
189
pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
191
Gdk::Rectangle col_rect;
192
Gdk::Rectangle row_rect;
193
Gdk::Rectangle grid_rect;
195
if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
198
_column_labels_border_x = col_overhang;
202
col_rect.set_width (min (col.first, _alloc_width));
204
uint32_t const y = min (_alloc_height, col.second);
205
col_rect.set_height (y);
207
row_rect.set_height (_alloc_height - y);
209
grid_rect.set_height (_alloc_height - y);
212
if (_alloc_width > (grid.first + row.first)) {
214
} else if (_alloc_width > row.first) {
215
x = _alloc_width - row.first;
218
grid_rect.set_width (x);
220
row_rect.set_width (_alloc_width - x);
223
} else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
225
col_rect.set_height (min (_alloc_height, col.second));
226
row_rect.set_height (std::min (_alloc_height - col_rect.get_height(), row.second));
229
row_rect.set_y (_alloc_height - row_rect.get_height() - col_rect.get_height());
230
row_rect.set_width (min (_alloc_width, row.first));
232
grid_rect.set_x (row_rect.get_width());
233
grid_rect.set_y (_alloc_height - row_rect.get_height() - col_rect.get_height());
234
grid_rect.set_width (std::min (_alloc_width - row_rect.get_width(), grid.first));
235
grid_rect.set_height (row_rect.get_height ());
237
col_rect.set_width (grid_rect.get_width () + col_overhang);
238
col_rect.set_x (row_rect.get_width() + grid_rect.get_width() - col_rect.get_width());
239
_column_labels_border_x = col_rect.get_x () >= 0 ? col_rect.get_x () : 0;
240
col_rect.set_y (_alloc_height - col_rect.get_height());
243
_column_labels_height = col_rect.get_height ();
245
_row_labels->set_parent_rectangle (row_rect);
246
_column_labels->set_parent_rectangle (col_rect);
247
_grid->set_parent_rectangle (grid_rect);
249
DimensionsChanged (); /* EMIT SIGNAL */
253
PortMatrixBody::setup ()
255
/* Discard any old connections to bundles */
257
_bundle_connections.drop_connections ();
259
/* Connect to bundles so that we find out when their names change */
261
if (_matrix->visible_rows()) {
262
PortGroup::BundleList r = _matrix->visible_rows()->bundles ();
263
for (PortGroup::BundleList::iterator i = r.begin(); i != r.end(); ++i) {
265
(*i)->bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&PortMatrixBody::rebuild_and_draw_row_labels, this), gui_context());
270
if (_matrix->visible_columns()) {
271
PortGroup::BundleList c = _matrix->visible_columns()->bundles ();
272
for (PortGroup::BundleList::iterator i = c.begin(); i != c.end(); ++i) {
273
(*i)->bundle->Changed.connect (_bundle_connections, invalidator (*this), boost::bind (&PortMatrixBody::rebuild_and_draw_column_labels, this), gui_context());
277
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
281
set_mouseover (PortMatrixNode ());
283
_ignore_component_size_changed = true;
284
compute_rectangles ();
285
_ignore_component_size_changed = false;
289
PortMatrixBody::full_scroll_width ()
291
return _grid->dimensions().first;
296
PortMatrixBody::alloc_scroll_width ()
298
return _grid->parent_rectangle().get_width();
302
PortMatrixBody::full_scroll_height ()
304
return _grid->dimensions().second;
308
PortMatrixBody::alloc_scroll_height ()
310
return _grid->parent_rectangle().get_height();
313
/** Set x offset (for scrolling) */
315
PortMatrixBody::set_xoffset (uint32_t xo)
321
/** Set y offset (for scrolling) */
323
PortMatrixBody::set_yoffset (uint32_t yo)
330
PortMatrixBody::on_button_press_event (GdkEventButton* ev)
332
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
333
if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
335
(*i)->parent_to_component_x (ev->x),
336
(*i)->parent_to_component_y (ev->y),
346
PortMatrixBody::on_button_release_event (GdkEventButton* ev)
348
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
349
if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
350
(*i)->button_release (
351
(*i)->parent_to_component_x (ev->x),
352
(*i)->parent_to_component_y (ev->y),
356
(*i)->button_release (
367
PortMatrixBody::rebuild_and_draw_grid ()
369
_grid->require_rebuild ();
374
PortMatrixBody::rebuild_and_draw_column_labels ()
376
_column_labels->require_rebuild ();
381
PortMatrixBody::rebuild_and_draw_row_labels ()
383
_row_labels->require_rebuild ();
388
PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
390
if (ev->type == GDK_LEAVE_NOTIFY) {
391
set_mouseover (PortMatrixNode ());
398
PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
402
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
403
if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
405
(*i)->parent_to_component_x (ev->x),
406
(*i)->parent_to_component_y (ev->y)
415
set_mouseover (PortMatrixNode ());
422
PortMatrixBody::set_mouseover (PortMatrixNode const & n)
424
list<PortMatrixNode> m;
430
PortMatrixBody::set_mouseover (list<PortMatrixNode> const & n)
432
if (n == _mouseover) {
436
/* Channel highlights are set up only on mouseovers, so
437
it's reasonable to remove all channel highlights here.
438
We can't let individual components clear their own highlights
439
because of the case where, say, the row labels set up some column
440
highlights, and then we ask the column labels to set up their
441
own highlights and they clear them out before they start.
444
_row_labels->clear_channel_highlights ();
445
_column_labels->clear_channel_highlights ();
447
list<PortMatrixNode> old = _mouseover;
450
for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
451
(*i)->mouseover_changed (old);
456
PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h)
458
ARDOUR::BundleChannel bc[2];
461
if (!PortMatrix::bundle_with_channels (bc[dim].bundle)) {
465
if (dim == _matrix->column_index()) {
466
_column_labels->add_channel_highlight (bc[dim]);
468
_row_labels->add_channel_highlight (bc[dim]);
471
PortGroup::BundleList const b = _matrix->visible_ports(1 - dim)->bundles ();
473
for (PortGroup::BundleList::const_iterator i = b.begin(); i != b.end(); ++i) {
474
for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
476
if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
480
bc[1 - dim] = ARDOUR::BundleChannel ((*i)->bundle, j);
483
n.row = bc[_matrix->row_index()];
484
n.column = bc[_matrix->column_index()];
486
if (_matrix->get_association(n) != PortMatrixNode::NOT_ASSOCIATED) {
487
if (dim == _matrix->column_index()) {
488
_row_labels->add_channel_highlight (bc[1 - dim]);
490
_column_labels->add_channel_highlight (bc[1 - dim]);
498
PortMatrixBody::set_cairo_clip (cairo_t* cr, Gdk::Rectangle const & r) const
500
cairo_rectangle (cr, r.get_x(), r.get_y(), r.get_width(), r.get_height());
505
PortMatrixBody::component_size_changed ()
507
if (_ignore_component_size_changed) {
511
compute_rectangles ();
512
_matrix->setup_scrollbars ();
515
pair<uint32_t, uint32_t>
516
PortMatrixBody::max_size () const
518
pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
519
pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
520
pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
522
return make_pair (std::max (row.first, _column_labels->overhang()) + grid.first, col.second + grid.second);
525
/** @return x position at which the column labels meet the border of the matrix */
527
PortMatrixBody::column_labels_border_x () const
529
return _column_labels_border_x;
533
PortMatrixBody::column_labels_height () const
535
return _column_labels_height;