More logical arrangement of port matrix inputs and outputs, hopefully;
[ardour.git] / gtk2_ardour / port_matrix_body.cc
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 "ardour/bundle.h"
22 #include "port_matrix_body.h"
23 #include "port_matrix.h"
24
25 PortMatrixBody::PortMatrixBody (PortMatrix* p, Arrangement a)
26         : _port_matrix (p),
27           _column_labels (this, a == TOP_AND_RIGHT ? PortMatrixColumnLabels::TOP : PortMatrixColumnLabels::BOTTOM),
28           _row_labels (p, this, a == BOTTOM_AND_LEFT ? PortMatrixRowLabels::LEFT : PortMatrixRowLabels::RIGHT),
29           _grid (p, this),
30           _arrangement (a),
31           _xoffset (0),
32           _yoffset (0)
33 {
34         modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#00000"));
35 }
36
37
38 bool
39 PortMatrixBody::on_expose_event (GdkEventExpose* event)
40 {
41         Gdk::Rectangle const exposure (
42                 event->area.x, event->area.y, event->area.width, event->area.height
43                 );
44
45         bool intersects;
46         Gdk::Rectangle r = exposure;
47         r.intersect (_column_labels_rect, intersects);
48
49         if (intersects) {
50                 gdk_draw_drawable (
51                         get_window()->gobj(),
52                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
53                         _column_labels.get_pixmap (get_window()->gobj()),
54                         r.get_x() - _column_labels_rect.get_x() + _xoffset,
55                         r.get_y() - _column_labels_rect.get_y(),
56                         r.get_x(),
57                         r.get_y(),
58                         r.get_width(),
59                         r.get_height()
60                         );
61         }
62
63         r = exposure;
64         r.intersect (_row_labels_rect, intersects);
65
66         if (intersects) {
67                 gdk_draw_drawable (
68                         get_window()->gobj(),
69                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
70                         _row_labels.get_pixmap (get_window()->gobj()),
71                         r.get_x() - _row_labels_rect.get_x(),
72                         r.get_y() - _row_labels_rect.get_y() + _yoffset,
73                         r.get_x(),
74                         r.get_y(),
75                         r.get_width(),
76                         r.get_height()
77                         );
78         }
79
80         r = exposure;
81         r.intersect (_grid_rect, intersects);
82
83         if (intersects) {
84                 gdk_draw_drawable (
85                         get_window()->gobj(),
86                         get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
87                         _grid.get_pixmap (get_window()->gobj()),
88                         r.get_x() - _grid_rect.get_x() + _xoffset,
89                         r.get_y() - _grid_rect.get_y() + _yoffset,
90                         r.get_x(),
91                         r.get_y(),
92                         r.get_width(),
93                         r.get_height()
94                         );
95         }
96
97         return true;
98 }
99
100 void
101 PortMatrixBody::on_size_request (Gtk::Requisition *req)
102 {
103         std::pair<int, int> const col = _column_labels.dimensions ();
104         std::pair<int, int> const row = _row_labels.dimensions ();
105         std::pair<int, int> const grid = _grid.dimensions ();
106
107         req->width = std::max (col.first, grid.first + row.first);
108         req->height = col.second + grid.second;
109 }
110
111 void
112 PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
113 {
114         Gtk::EventBox::on_size_allocate (alloc);
115         set_allocation (alloc);
116
117         _alloc_width = alloc.get_width ();
118         _alloc_height = alloc.get_height ();
119
120         compute_rectangles ();
121         _port_matrix->setup_scrollbars ();
122 }
123
124 void
125 PortMatrixBody::compute_rectangles ()
126 {
127         /* full sizes of components */
128         std::pair<uint32_t, uint32_t> const col = _column_labels.dimensions ();
129         std::pair<uint32_t, uint32_t> const row = _row_labels.dimensions ();
130         std::pair<uint32_t, uint32_t> const grid = _grid.dimensions ();
131
132         if (_arrangement == TOP_AND_RIGHT) {
133
134                 /* build from top left */
135
136                 _column_labels_rect.set_x (0);
137                 _column_labels_rect.set_y (0);
138                 _grid_rect.set_x (0);
139
140                 if (_alloc_width > col.first) {
141                         _column_labels_rect.set_width (col.first);
142                 } else {
143                         _column_labels_rect.set_width (_alloc_width);
144                 }
145
146                 /* move down to y division */
147                 
148                 uint32_t y = 0;
149                 if (_alloc_height > col.second) {
150                         y = col.second;
151                 } else {
152                         y = _alloc_height;
153                 }
154
155                 _column_labels_rect.set_height (y);
156                 _row_labels_rect.set_y (y);
157                 _row_labels_rect.set_height (_alloc_height - y);
158                 _grid_rect.set_y (y);
159                 _grid_rect.set_height (_alloc_height - y);
160
161                 /* move right to x division */
162
163                 uint32_t x = 0;
164                 if (_alloc_width > (grid.first + row.first)) {
165                         x = grid.first;
166                 } else if (_alloc_width > row.first) {
167                         x = _alloc_width - row.first;
168                 }
169
170                 _grid_rect.set_width (x);
171                 _row_labels_rect.set_x (x);
172                 _row_labels_rect.set_width (_alloc_width - x);
173                         
174
175         } else if (_arrangement == BOTTOM_AND_LEFT) {
176
177                 /* build from bottom right */
178
179                 /* move left to x division */
180
181                 uint32_t x = 0;
182                 if (_alloc_width > (grid.first + row.first)) {
183                         x = grid.first;
184                 } else if (_alloc_width > row.first) {
185                         x = _alloc_width - row.first;
186                 }
187
188                 _grid_rect.set_x (_alloc_width - x);
189                 _grid_rect.set_width (x);
190                 _column_labels_rect.set_width (std::min (_alloc_width, col.first));
191                 _column_labels_rect.set_x (_alloc_width - _column_labels_rect.get_width());
192
193                 _row_labels_rect.set_width (std::min (_alloc_width - x, row.first));
194                 _row_labels_rect.set_x (_alloc_width - x - _row_labels_rect.get_width());
195
196                 /* move up to the y division */
197                 
198                 uint32_t y = 0;
199                 if (_alloc_height > col.second) {
200                         y = col.second;
201                 } else {
202                         y = _alloc_height;
203                 }
204
205                 _column_labels_rect.set_y (_alloc_height - y);
206                 _column_labels_rect.set_height (y);
207
208                 _grid_rect.set_height (std::min (grid.second, _alloc_height - y));
209                 _grid_rect.set_y (_alloc_height - y - _grid_rect.get_height());
210
211                 _row_labels_rect.set_height (_grid_rect.get_height());
212                 _row_labels_rect.set_y (_grid_rect.get_y());
213
214         }
215 }
216
217 void
218 PortMatrixBody::setup (
219         std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & row,
220         std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & column
221         )
222 {
223         for (std::list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) {
224                 i->disconnect ();
225         }
226
227         _bundle_connections.clear ();
228         
229         _row_bundles = row;
230         _column_bundles = column;
231
232         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _row_bundles.begin(); i != _row_bundles.end(); ++i) {
233                 
234                 _bundle_connections.push_back (
235                         (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_row_labels))
236                         );
237                 
238         }
239
240         for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _column_bundles.begin(); i != _column_bundles.end(); ++i) {
241                 _bundle_connections.push_back (
242                         (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_column_labels))
243                         );
244         }
245         
246         _column_labels.setup ();
247         _row_labels.setup ();
248         _grid.setup ();
249
250         compute_rectangles ();
251 }
252
253 uint32_t
254 PortMatrixBody::full_scroll_width ()
255 {
256         return _grid.dimensions().first;
257
258 }
259
260 uint32_t
261 PortMatrixBody::alloc_scroll_width ()
262 {
263         return _grid_rect.get_width();
264 }
265
266 uint32_t
267 PortMatrixBody::full_scroll_height ()
268 {
269         return _grid.dimensions().second;
270 }
271
272 uint32_t
273 PortMatrixBody::alloc_scroll_height ()
274 {
275         return _grid_rect.get_height();
276 }
277
278 void
279 PortMatrixBody::set_xoffset (uint32_t xo)
280 {
281         _xoffset = xo;
282         queue_draw ();
283 }
284
285 void
286 PortMatrixBody::set_yoffset (uint32_t yo)
287 {
288         _yoffset = yo;
289         queue_draw ();
290 }
291
292 bool
293 PortMatrixBody::on_button_press_event (GdkEventButton* ev)
294 {
295         if (Gdk::Region (_grid_rect).point_in (ev->x, ev->y)) {
296
297                 _grid.button_press (
298                         ev->x - _grid_rect.get_x() + _xoffset,
299                         ev->y - _grid_rect.get_y() + _yoffset,
300                         ev->button
301                         );
302
303         } else if (Gdk::Region (_row_labels_rect).point_in (ev->x, ev->y)) {
304
305                 _row_labels.button_press (
306                         ev->x - _row_labels_rect.get_x(),
307                         ev->y - _row_labels_rect.get_y() + _yoffset,
308                         ev->button, ev->time
309                         );
310         
311         } else {
312         
313                 return false;
314                 
315         }
316
317         return true;
318 }
319
320 void
321 PortMatrixBody::repaint_grid ()
322 {
323         _grid.require_render ();
324         queue_draw ();
325 }
326
327 void
328 PortMatrixBody::repaint_column_labels ()
329 {
330         _column_labels.require_render ();
331         queue_draw ();
332 }
333
334 void
335 PortMatrixBody::repaint_row_labels ()
336 {
337         _row_labels.require_render ();
338         queue_draw ();
339 }