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),
34 modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#00000"));
35 add_events (Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK);
40 PortMatrixBody::on_expose_event (GdkEventExpose* event)
42 Gdk::Rectangle const exposure (
43 event->area.x, event->area.y, event->area.width, event->area.height
47 Gdk::Rectangle r = exposure;
48 r.intersect (_column_labels.parent_rectangle(), intersects);
53 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
54 _column_labels.get_pixmap (get_window()->gobj()),
55 _column_labels.parent_to_component_x (r.get_x()),
56 _column_labels.parent_to_component_y (r.get_y()),
65 r.intersect (_row_labels.parent_rectangle(), intersects);
70 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
71 _row_labels.get_pixmap (get_window()->gobj()),
72 _row_labels.parent_to_component_x (r.get_x()),
73 _row_labels.parent_to_component_y (r.get_y()),
82 r.intersect (_grid.parent_rectangle(), intersects);
87 get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
88 _grid.get_pixmap (get_window()->gobj()),
89 _grid.parent_to_component_x (r.get_x()),
90 _grid.parent_to_component_y (r.get_y()),
98 cairo_t* cr = gdk_cairo_create (get_window()->gobj());
99 _grid.draw_extra (cr);
100 _row_labels.draw_extra (cr);
101 _column_labels.draw_extra (cr);
108 PortMatrixBody::on_size_request (Gtk::Requisition *req)
110 std::pair<int, int> const col = _column_labels.dimensions ();
111 std::pair<int, int> const row = _row_labels.dimensions ();
112 std::pair<int, int> const grid = _grid.dimensions ();
114 /* don't ask for the maximum size of our contents, otherwise GTK won't
115 let the containing window shrink below this size */
117 req->width = std::min (512, std::max (col.first, grid.first + row.first));
118 req->height = std::min (512, col.second + grid.second);
122 PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
124 Gtk::EventBox::on_size_allocate (alloc);
126 _alloc_width = alloc.get_width ();
127 _alloc_height = alloc.get_height ();
129 compute_rectangles ();
130 _matrix->setup_scrollbars ();
134 PortMatrixBody::compute_rectangles ()
136 /* full sizes of components */
137 std::pair<uint32_t, uint32_t> const col = _column_labels.dimensions ();
138 std::pair<uint32_t, uint32_t> const row = _row_labels.dimensions ();
139 std::pair<uint32_t, uint32_t> const grid = _grid.dimensions ();
141 Gdk::Rectangle col_rect;
142 Gdk::Rectangle row_rect;
143 Gdk::Rectangle grid_rect;
145 if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) {
147 /* build from top left */
153 if (_alloc_width > col.first) {
154 col_rect.set_width (col.first);
156 col_rect.set_width (_alloc_width);
159 /* move down to y division */
162 if (_alloc_height > col.second) {
168 col_rect.set_height (y);
170 row_rect.set_height (_alloc_height - y);
172 grid_rect.set_height (_alloc_height - y);
174 /* move right to x division */
177 if (_alloc_width > (grid.first + row.first)) {
179 } else if (_alloc_width > row.first) {
180 x = _alloc_width - row.first;
183 grid_rect.set_width (x);
185 row_rect.set_width (_alloc_width - x);
188 } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
190 /* build from bottom right */
192 /* move left to x division */
195 if (_alloc_width > (grid.first + row.first)) {
197 } else if (_alloc_width > row.first) {
198 x = _alloc_width - row.first;
201 grid_rect.set_x (_alloc_width - x);
202 grid_rect.set_width (x);
203 col_rect.set_width (col.first - grid.first + x);
204 col_rect.set_x (_alloc_width - col_rect.get_width());
206 row_rect.set_width (std::min (_alloc_width - x, row.first));
207 row_rect.set_x (_alloc_width - x - row_rect.get_width());
209 /* move up to the y division */
212 if (_alloc_height > col.second) {
218 col_rect.set_y (_alloc_height - y);
219 col_rect.set_height (y);
221 grid_rect.set_height (std::min (grid.second, _alloc_height - y));
222 grid_rect.set_y (_alloc_height - y - grid_rect.get_height());
224 row_rect.set_height (grid_rect.get_height());
225 row_rect.set_y (grid_rect.get_y());
228 _row_labels.set_parent_rectangle (row_rect);
229 _column_labels.set_parent_rectangle (col_rect);
230 _grid.set_parent_rectangle (grid_rect);
234 PortMatrixBody::setup ()
236 /* Discard any old connections to bundles */
238 for (std::list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) {
241 _bundle_connections.clear ();
243 /* Connect to bundles so that we find out when their names change */
245 ARDOUR::BundleList r = _matrix->rows()->bundles ();
246 for (ARDOUR::BundleList::iterator i = r.begin(); i != r.end(); ++i) {
248 _bundle_connections.push_back (
249 (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_row_labels))
254 ARDOUR::BundleList c = _matrix->columns()->bundles ();
255 for (ARDOUR::BundleList::iterator i = c.begin(); i != c.end(); ++i) {
256 _bundle_connections.push_back (
257 (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels))
261 _column_labels.setup ();
262 _row_labels.setup ();
265 set_mouseover (PortMatrixNode ());
266 compute_rectangles ();
270 PortMatrixBody::full_scroll_width ()
272 return _grid.dimensions().first;
277 PortMatrixBody::alloc_scroll_width ()
279 return _grid.parent_rectangle().get_width();
283 PortMatrixBody::full_scroll_height ()
285 return _grid.dimensions().second;
289 PortMatrixBody::alloc_scroll_height ()
291 return _grid.parent_rectangle().get_height();
295 PortMatrixBody::set_xoffset (uint32_t xo)
302 PortMatrixBody::set_yoffset (uint32_t yo)
309 PortMatrixBody::on_button_press_event (GdkEventButton* ev)
311 if (Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) {
314 _grid.parent_to_component_x (ev->x),
315 _grid.parent_to_component_y (ev->y),
319 } else if (Gdk::Region (_row_labels.parent_rectangle()).point_in (ev->x, ev->y)) {
321 _row_labels.button_press (
322 _row_labels.parent_to_component_x (ev->x),
323 _row_labels.parent_to_component_y (ev->y),
327 } else if (Gdk::Region (_column_labels.parent_rectangle()).point_in (ev->x, ev->y)) {
329 _column_labels.button_press (
330 _column_labels.parent_to_component_x (ev->x),
331 _column_labels.parent_to_component_y (ev->y),
340 PortMatrixBody::rebuild_and_draw_grid ()
342 _grid.require_rebuild ();
347 PortMatrixBody::rebuild_and_draw_column_labels ()
349 _column_labels.require_rebuild ();
354 PortMatrixBody::rebuild_and_draw_row_labels ()
356 _row_labels.require_rebuild ();
361 PortMatrixBody::on_leave_notify_event (GdkEventCrossing* ev)
363 if (ev->type == GDK_LEAVE_NOTIFY) {
364 set_mouseover (PortMatrixNode ());
371 PortMatrixBody::on_motion_notify_event (GdkEventMotion* ev)
373 if (Gdk::Region (_grid.parent_rectangle()).point_in (ev->x, ev->y)) {
374 _grid.mouseover_event (
375 _grid.parent_to_component_x (ev->x),
376 _grid.parent_to_component_y (ev->y)
384 PortMatrixBody::set_mouseover (PortMatrixNode const & n)
386 if (n == _mouseover) {
390 PortMatrixNode old = _mouseover;
393 _grid.mouseover_changed (old);
394 _row_labels.mouseover_changed (old);
395 _column_labels.mouseover_changed (old);