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"
26 PortMatrixBody::PortMatrixBody (PortMatrix* p)
28 _column_labels (p, this),
29 _row_labels (p, this),
33 _mouse_over_grid (false)
35 modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#00000"));
36 add_events (Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK);
41 PortMatrixBody::on_expose_event (GdkEventExpose* event)
43 Gdk::Rectangle const exposure (
44 event->area.x, event->area.y, event->area.width, event->area.height
48 Gdk::Rectangle r = exposure;
49 r.intersect (_column_labels.parent_rectangle(), intersects);
54 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
55 _column_labels.get_pixmap (get_window()->gobj()),
56 _column_labels.parent_to_component_x (r.get_x()),
57 _column_labels.parent_to_component_y (r.get_y()),
66 r.intersect (_row_labels.parent_rectangle(), intersects);
71 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
72 _row_labels.get_pixmap (get_window()->gobj()),
73 _row_labels.parent_to_component_x (r.get_x()),
74 _row_labels.parent_to_component_y (r.get_y()),
83 r.intersect (_grid.parent_rectangle(), intersects);
88 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
89 _grid.get_pixmap (get_window()->gobj()),
90 _grid.parent_to_component_x (r.get_x()),
91 _grid.parent_to_component_y (r.get_y()),
99 cairo_t* cr = gdk_cairo_create (get_window()->gobj());
100 _grid.draw_extra (cr);
101 _row_labels.draw_extra (cr);
102 _column_labels.draw_extra (cr);
109 PortMatrixBody::on_size_request (Gtk::Requisition *req)
111 std::pair<int, int> const col = _column_labels.dimensions ();
112 std::pair<int, int> const row = _row_labels.dimensions ();
113 std::pair<int, int> const grid = _grid.dimensions ();
115 /* don't ask for the maximum size of our contents, otherwise GTK won't
116 let the containing window shrink below this size */
118 req->width = std::min (512, std::max (col.first, grid.first + row.first));
119 req->height = std::min (512, col.second + grid.second);
123 PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
125 Gtk::EventBox::on_size_allocate (alloc);
127 _alloc_width = alloc.get_width ();
128 _alloc_height = alloc.get_height ();
130 compute_rectangles ();
131 _matrix->setup_scrollbars ();
135 PortMatrixBody::compute_rectangles ()
137 /* full sizes of components */
138 std::pair<uint32_t, uint32_t> const col = _column_labels.dimensions ();
139 std::pair<uint32_t, uint32_t> const row = _row_labels.dimensions ();
140 std::pair<uint32_t, uint32_t> const grid = _grid.dimensions ();
142 Gdk::Rectangle col_rect;
143 Gdk::Rectangle row_rect;
144 Gdk::Rectangle grid_rect;
146 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
148 /* build from top left */
154 if (_alloc_width > col.first) {
155 col_rect.set_width (col.first);
157 col_rect.set_width (_alloc_width);
160 /* move down to y division */
163 if (_alloc_height > col.second) {
169 col_rect.set_height (y);
171 row_rect.set_height (_alloc_height - y);
173 grid_rect.set_height (_alloc_height - y);
175 /* move right to x division */
178 if (_alloc_width > (grid.first + row.first)) {
180 } else if (_alloc_width > row.first) {
181 x = _alloc_width - row.first;
184 grid_rect.set_width (x);
186 row_rect.set_width (_alloc_width - x);
189 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
191 /* build from bottom right */
193 /* move left to x division */
196 if (_alloc_width > (grid.first + row.first)) {
198 } else if (_alloc_width > row.first) {
199 x = _alloc_width - row.first;
202 grid_rect.set_x (_alloc_width - x);
203 grid_rect.set_width (x);
204 col_rect.set_width (col.first - grid.first + x);
205 col_rect.set_x (_alloc_width - col_rect.get_width());
207 row_rect.set_width (std::min (_alloc_width - x, row.first));
208 row_rect.set_x (_alloc_width - x - row_rect.get_width());
210 /* move up to the y division */
213 if (_alloc_height > col.second) {
219 col_rect.set_y (_alloc_height - y);
220 col_rect.set_height (y);
222 grid_rect.set_height (std::min (grid.second, _alloc_height - y));
223 grid_rect.set_y (_alloc_height - y - grid_rect.get_height());
225 row_rect.set_height (grid_rect.get_height());
226 row_rect.set_y (grid_rect.get_y());
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 (std::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 ARDOUR::BundleList r = _matrix->rows()->bundles ();
247 for (ARDOUR::BundleList::iterator i = r.begin(); i != r.end(); ++i) {
249 _bundle_connections.push_back (
250 (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_row_labels))
255 ARDOUR::BundleList c = _matrix->columns()->bundles ();
256 for (ARDOUR::BundleList::iterator i = c.begin(); i != c.end(); ++i) {
257 _bundle_connections.push_back (
258 (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels))
262 _column_labels.setup ();
263 _row_labels.setup ();
266 set_mouseover (PortMatrixNode ());
267 compute_rectangles ();
271 PortMatrixBody::full_scroll_width ()
273 return _grid.dimensions().first;
278 PortMatrixBody::alloc_scroll_width ()
280 return _grid.parent_rectangle().get_width();
284 PortMatrixBody::full_scroll_height ()
286 return _grid.dimensions().second;
290 PortMatrixBody::alloc_scroll_height ()
292 return _grid.parent_rectangle().get_height();
296 PortMatrixBody::set_xoffset (uint32_t xo)
303 PortMatrixBody::set_yoffset (uint32_t yo)
310 PortMatrixBody::on_button_press_event (GdkEventButton* ev)
312 if (Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) {
315 _grid.parent_to_component_x (ev->x),
316 _grid.parent_to_component_y (ev->y),
320 } else if (Gdk::Region (_row_labels.parent_rectangle()).point_in (ev->x, ev->y)) {
322 _row_labels.button_press (
323 _row_labels.parent_to_component_x (ev->x),
324 _row_labels.parent_to_component_y (ev->y),
328 } else if (Gdk::Region (_column_labels.parent_rectangle()).point_in (ev->x, ev->y)) {
330 _column_labels.button_press (
331 _column_labels.parent_to_component_x (ev->x),
332 _column_labels.parent_to_component_y (ev->y),
341 PortMatrixBody::on_button_release_event (GdkEventButton* ev)
343 if (Gdk::Region (_row_labels.parent_rectangle()).point_in (ev->x, ev->y) ||
344 Gdk::Region (_column_labels.parent_rectangle()).point_in (ev->x, ev->y)) {
346 _row_labels.clear_channel_highlights ();
347 _column_labels.clear_channel_highlights ();
355 PortMatrixBody::rebuild_and_draw_grid ()
357 _grid.require_rebuild ();
362 PortMatrixBody::rebuild_and_draw_column_labels ()
364 _column_labels.require_rebuild ();
369 PortMatrixBody::rebuild_and_draw_row_labels ()
371 _row_labels.require_rebuild ();
376 PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
378 if (ev->type == GDK_LEAVE_NOTIFY) {
379 set_mouseover (PortMatrixNode ());
386 PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
388 if (Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) {
389 _grid.mouseover_event (
390 _grid.parent_to_component_x (ev->x),
391 _grid.parent_to_component_y (ev->y)
393 _mouse_over_grid = true;
395 if (_mouse_over_grid) {
396 set_mouseover (PortMatrixNode ());
397 _mouse_over_grid = false;
405 PortMatrixBody::set_mouseover (PortMatrixNode const & n)
407 if (n == _mouseover) {
411 PortMatrixNode old = _mouseover;
414 _grid.mouseover_changed (old);
415 _row_labels.mouseover_changed (old);
416 _column_labels.mouseover_changed (old);
422 PortMatrixBody::highlight_associated_channels (int dim, uint32_t N)
424 ARDOUR::BundleChannel bc[2];
426 ARDOUR::BundleList const a = _matrix->ports(dim)->bundles ();
427 for (ARDOUR::BundleList::const_iterator i = a.begin(); i != a.end(); ++i) {
428 if (N < (*i)->nchannels ()) {
429 bc[dim] = ARDOUR::BundleChannel (*i, N);
432 N -= (*i)->nchannels ();
436 if (!bc[dim].bundle) {
440 if (dim == _matrix->column_index()) {
441 _column_labels.add_channel_highlight (bc[dim]);
443 _row_labels.add_channel_highlight (bc[dim]);
446 ARDOUR::BundleList const b = _matrix->ports(1 - dim)->bundles ();
448 for (ARDOUR::BundleList::const_iterator i = b.begin(); i != b.end(); ++i) {
449 for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
450 bc[1 - dim] = ARDOUR::BundleChannel (*i, j);
451 if (_matrix->get_state (bc) == PortMatrix::ASSOCIATED) {
452 if (dim == _matrix->column_index()) {
453 _row_labels.add_channel_highlight (bc[1 - dim]);
455 _column_labels.add_channel_highlight (bc[1 - dim]);