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"
23 #include "port_matrix_body.h"
24 #include "port_matrix.h"
25 #include "port_matrix_column_labels.h"
26 #include "port_matrix_row_labels.h"
27 #include "port_matrix_grid.h"
31 PortMatrixBody::PortMatrixBody (PortMatrix* p)
37 _ignore_component_size_changed (false)
39 _column_labels = new PortMatrixColumnLabels (p, this);
40 _row_labels = new PortMatrixRowLabels (p, this);
41 _grid = new PortMatrixGrid (p, this);
43 _components.push_back (_column_labels);
44 _components.push_back (_row_labels);
45 _components.push_back (_grid);
47 add_events (Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK);
51 PortMatrixBody::~PortMatrixBody ()
53 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
59 PortMatrixBody::on_expose_event (GdkEventExpose* event)
61 if (_matrix->visible_columns()->bundles().empty() || _matrix->visible_rows()->bundles().empty()) {
63 /* nothing to connect */
65 cairo_t* cr = gdk_cairo_create (get_window()->gobj());
67 cairo_set_source_rgb (cr, 0, 0, 0);
68 cairo_rectangle (cr, 0, 0, _alloc_width, _alloc_height);
72 t << _("There are no ") << (_matrix->type() == ARDOUR::DataType::AUDIO ? _("audio") : _("MIDI")) << _(" ports to connect.");
74 cairo_text_extents_t ext;
75 cairo_text_extents (cr, t.str().c_str(), &ext);
77 cairo_set_source_rgb (cr, 1, 1, 1);
78 cairo_move_to (cr, (_alloc_width - ext.width) / 2, (_alloc_height + ext.height) / 2);
79 cairo_show_text (cr, t.str().c_str ());
86 Gdk::Rectangle const exposure (
87 event->area.x, event->area.y, event->area.width, event->area.height
92 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
94 Gdk::Rectangle r = exposure;
96 /* the get_pixmap call may cause things to be rerendered and sizes to change,
97 so fetch the pixmap before calculating where to put it */
98 GdkPixmap* p = (*i)->get_pixmap (get_window()->gobj());
99 r.intersect ((*i)->parent_rectangle(), intersects);
104 get_window()->gobj(),
105 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
107 (*i)->parent_to_component_x (r.get_x()),
108 (*i)->parent_to_component_y (r.get_y()),
118 cairo_t* cr = gdk_cairo_create (get_window()->gobj());
120 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
122 set_cairo_clip (cr, (*i)->parent_rectangle ());
123 (*i)->draw_extra (cr);
133 PortMatrixBody::on_size_request (Gtk::Requisition *req)
135 pair<int, int> const col = _column_labels->dimensions ();
136 pair<int, int> const row = _row_labels->dimensions ();
137 pair<int, int> const grid = _grid->dimensions ();
139 if (grid.first == 0 && grid.second == 0) {
140 /* nothing to display */
146 /* don't ask for the maximum size of our contents, otherwise GTK won't
147 let the containing window shrink below this size */
149 /* XXX these shouldn't be hard-coded */
150 int const min_width = 512;
151 int const min_height = 512;
153 req->width = min (min_width, max (col.first, grid.first + row.first));
154 req->height = min (min_height / _matrix->min_height_divisor(), col.second + grid.second);
158 PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
160 Gtk::EventBox::on_size_allocate (alloc);
162 _alloc_width = alloc.get_width ();
163 _alloc_height = alloc.get_height ();
165 compute_rectangles ();
166 _matrix->setup_scrollbars ();
170 PortMatrixBody::compute_rectangles ()
172 /* full sizes of components */
173 pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
174 uint32_t col_overhang = _column_labels->overhang ();
175 pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
176 pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
178 Gdk::Rectangle col_rect;
179 Gdk::Rectangle row_rect;
180 Gdk::Rectangle grid_rect;
182 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
188 col_rect.set_width (min (col.first, _alloc_width));
190 uint32_t const y = min (_alloc_height, col.second);
191 col_rect.set_height (y);
193 row_rect.set_height (_alloc_height - y);
195 grid_rect.set_height (_alloc_height - y);
198 if (_alloc_width > (grid.first + row.first)) {
200 } else if (_alloc_width > row.first) {
201 x = _alloc_width - row.first;
204 grid_rect.set_width (x);
206 row_rect.set_width (_alloc_width - x);
209 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
211 col_rect.set_height (min (_alloc_height, col.second));
215 row_rect.set_width (min (_alloc_width, row.first));
216 row_rect.set_height (std::min (_alloc_height - col_rect.get_height(), row.second));
218 grid_rect.set_x (row_rect.get_width());
220 grid_rect.set_width (std::min (_alloc_width - row_rect.get_width(), grid.first));
221 grid_rect.set_height (row_rect.get_height ());
223 col_rect.set_width (grid_rect.get_width () + col_overhang);
224 col_rect.set_x (row_rect.get_width() + grid_rect.get_width() - col_rect.get_width());
225 col_rect.set_y (row_rect.get_height());
229 _row_labels->set_parent_rectangle (row_rect);
230 _column_labels->set_parent_rectangle (col_rect);
231 _grid->set_parent_rectangle (grid_rect);
235 PortMatrixBody::setup ()
237 /* Discard any old connections to bundles */
239 for (list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) {
242 _bundle_connections.clear ();
244 /* Connect to bundles so that we find out when their names change */
246 PortGroup::BundleList r = _matrix->rows()->bundles ();
247 for (PortGroup::BundleList::iterator i = r.begin(); i != r.end(); ++i) {
249 _bundle_connections.push_back (
250 i->bundle->Changed.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_row_labels)))
255 PortGroup::BundleList c = _matrix->columns()->bundles ();
256 for (PortGroup::BundleList::iterator i = c.begin(); i != c.end(); ++i) {
257 _bundle_connections.push_back (
258 i->bundle->Changed.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels)))
262 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
266 set_mouseover (PortMatrixNode ());
268 _ignore_component_size_changed = true;
269 compute_rectangles ();
270 _ignore_component_size_changed = false;
274 PortMatrixBody::full_scroll_width ()
276 return _grid->dimensions().first;
281 PortMatrixBody::alloc_scroll_width ()
283 return _grid->parent_rectangle().get_width();
287 PortMatrixBody::full_scroll_height ()
289 return _grid->dimensions().second;
293 PortMatrixBody::alloc_scroll_height ()
295 return _grid->parent_rectangle().get_height();
299 PortMatrixBody::set_xoffset (uint32_t xo)
306 PortMatrixBody::set_yoffset (uint32_t yo)
313 PortMatrixBody::on_button_press_event (GdkEventButton* ev)
315 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
316 if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
318 (*i)->parent_to_component_x (ev->x),
319 (*i)->parent_to_component_y (ev->y),
329 PortMatrixBody::on_button_release_event (GdkEventButton* ev)
331 if (Gdk::Region (_grid->parent_rectangle()).point_in (ev->x, ev->y)) {
333 _grid->button_release (
334 _grid->parent_to_component_x (ev->x),
335 _grid->parent_to_component_y (ev->y),
345 PortMatrixBody::rebuild_and_draw_grid ()
347 _grid->require_rebuild ();
352 PortMatrixBody::rebuild_and_draw_column_labels ()
354 _column_labels->require_rebuild ();
359 PortMatrixBody::rebuild_and_draw_row_labels ()
361 _row_labels->require_rebuild ();
366 PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
368 if (ev->type == GDK_LEAVE_NOTIFY) {
369 set_mouseover (PortMatrixNode ());
376 PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
380 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
381 if (Gdk::Region ((*i)->parent_rectangle()).point_in (ev->x, ev->y)) {
383 (*i)->parent_to_component_x (ev->x),
384 (*i)->parent_to_component_y (ev->y)
393 set_mouseover (PortMatrixNode ());
400 PortMatrixBody::set_mouseover (PortMatrixNode const & n)
402 list<PortMatrixNode> m;
408 PortMatrixBody::set_mouseover (list<PortMatrixNode> const & n)
410 if (n == _mouseover) {
414 /* Channel highlights are set up only on mouseovers, so
415 it's reasonable to remove all channel highlights here.
416 We can't let individual components clear their own highlights
417 because of the case where, say, the row labels set up some column
418 highlights, and then we ask the column labels to set up their
419 own highlights and they clear them out before they start.
422 _row_labels->clear_channel_highlights ();
423 _column_labels->clear_channel_highlights ();
425 list<PortMatrixNode> old = _mouseover;
428 for (list<PortMatrixComponent*>::iterator i = _components.begin(); i != _components.end(); ++i) {
429 (*i)->mouseover_changed (old);
434 PortMatrixBody::highlight_associated_channels (int dim, ARDOUR::BundleChannel h)
436 ARDOUR::BundleChannel bc[2];
439 if (!bc[dim].bundle) {
443 if (dim == _matrix->column_index()) {
444 _column_labels->add_channel_highlight (bc[dim]);
446 _row_labels->add_channel_highlight (bc[dim]);
449 PortGroup::BundleList const b = _matrix->visible_ports(1 - dim)->bundles ();
451 for (PortGroup::BundleList::const_iterator i = b.begin(); i != b.end(); ++i) {
452 for (uint32_t j = 0; j < i->bundle->nchannels(); ++j) {
453 bc[1 - dim] = ARDOUR::BundleChannel (i->bundle, j);
454 if (_matrix->get_state (bc) == PortMatrixNode::ASSOCIATED) {
455 if (dim == _matrix->column_index()) {
456 _row_labels->add_channel_highlight (bc[1 - dim]);
458 _column_labels->add_channel_highlight (bc[1 - dim]);
466 PortMatrixBody::set_cairo_clip (cairo_t* cr, Gdk::Rectangle const & r) const
468 cairo_rectangle (cr, r.get_x(), r.get_y(), r.get_width(), r.get_height());
473 PortMatrixBody::component_size_changed ()
475 if (_ignore_component_size_changed) {
479 compute_rectangles ();
480 _matrix->setup_scrollbars ();
483 pair<uint32_t, uint32_t>
484 PortMatrixBody::max_size () const
486 pair<uint32_t, uint32_t> const col = _column_labels->dimensions ();
487 pair<uint32_t, uint32_t> const row = _row_labels->dimensions ();
488 pair<uint32_t, uint32_t> const grid = _grid->dimensions ();
490 return make_pair (std::max (row.first, _column_labels->overhang()) + grid.first, col.second + grid.second);