Delete trailing whitespace
[ardour.git] / gtk2_ardour / port_matrix_row_labels.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 <boost/weak_ptr.hpp>
22 #include <cairo/cairo.h>
23 #include "ardour/bundle.h"
24 #include "port_matrix_row_labels.h"
25 #include "port_matrix.h"
26 #include "port_matrix_body.h"
27 #include "i18n.h"
28 #include "utils.h"
29
30 using namespace std;
31
32 PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b)
33         : PortMatrixLabels (m, b)
34 {
35
36 }
37
38 void
39 PortMatrixRowLabels::compute_dimensions ()
40 {
41         GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
42         gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
43         cairo_t* cr = gdk_cairo_create (pm);
44
45         _longest_port_name = 0;
46         _longest_bundle_name = 0;
47
48         /* Compute maximum dimensions using all port groups, so that we allow for the largest and hence
49            we can change between visible groups without the size of the labels jumping around.
50         */
51
52         for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) {
53
54                 PortGroup::BundleList const r = (*i)->bundles ();
55                 for (PortGroup::BundleList::const_iterator j = r.begin(); j != r.end(); ++j) {
56
57                         for (uint32_t k = 0; k < (*j)->bundle->nchannels().n_total(); ++k) {
58
59                                 if (!_matrix->should_show ((*j)->bundle->channel_type(k))) {
60                                         continue;
61                                 }
62
63                                 cairo_text_extents_t ext;
64                                 cairo_text_extents (cr, (*j)->bundle->channel_name(k).c_str(), &ext);
65                                 if (ext.width > _longest_port_name) {
66                                         _longest_port_name = ext.width;
67                                 }
68                         }
69
70                         cairo_text_extents_t ext;
71                         cairo_text_extents (cr, (*j)->bundle->name().c_str(), &ext);
72                         if (ext.width > _longest_bundle_name) {
73                                 _longest_bundle_name = ext.width;
74                         }
75                 }
76         }
77
78
79         if (_matrix->visible_rows()) {
80                 _height = group_size (_matrix->visible_rows()) * grid_spacing ();
81         } else {
82                 _height = 0;
83         }
84
85         cairo_destroy (cr);
86         g_object_unref (pm);
87
88         _width = _longest_bundle_name +
89                 name_pad() * 2;
90
91         if (!_matrix->show_only_bundles()) {
92                 _width += _longest_port_name;
93                 _width += name_pad() * 2;
94         }
95 }
96
97
98 void
99 PortMatrixRowLabels::render (cairo_t* cr)
100 {
101         /* BACKGROUND */
102
103         set_source_rgb (cr, background_colour());
104         cairo_rectangle (cr, 0, 0, _width, _height);
105         cairo_fill (cr);
106
107         /* BUNDLE AND PORT NAMES */
108
109         double y = 0;
110         int N = 0;
111         int M = 0;
112
113         PortGroup::BundleList const & bundles = _matrix->visible_rows()->bundles ();
114         for (PortGroup::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) {
115                 render_bundle_name (cr, background_colour (), (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (N), 0, y, (*i)->bundle);
116
117                 if (!_matrix->show_only_bundles()) {
118                         for (uint32_t j = 0; j < (*i)->bundle->nchannels().n_total(); ++j) {
119
120                                 if (!_matrix->should_show ((*i)->bundle->channel_type(j))) {
121                                         continue;
122                                 }
123
124                                 Gdk::Color c = (*i)->has_colour ? (*i)->colour : get_a_bundle_colour (M);
125                                 render_channel_name (cr, background_colour (), c, 0, y, ARDOUR::BundleChannel ((*i)->bundle, j));
126                                 y += grid_spacing();
127                                 ++M;
128                         }
129                 } else {
130                         y += grid_spacing();
131                 }
132
133                 ++N;
134         }
135 }
136
137 void
138 PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t, guint)
139 {
140         ARDOUR::BundleChannel w = position_to_channel (y, x, _matrix->visible_rows());
141
142         if (
143                 (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_longest_port_name + name_pad() * 2)) ||
144                 (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < (_longest_bundle_name + name_pad() * 2))
145
146                 ) {
147                         w.channel = -1;
148         }
149
150         if (b == 3) {
151
152                 _matrix->popup_menu (
153                         ARDOUR::BundleChannel (),
154                         w,
155                         t
156                         );
157         }
158 }
159
160 double
161 PortMatrixRowLabels::component_to_parent_x (double x) const
162 {
163         /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
164         return x + _parent_rectangle.get_x();
165 }
166
167 double
168 PortMatrixRowLabels::parent_to_component_x (double x) const
169 {
170         /* Row labels don't scroll horizontally, so x conversion does not depend on xoffset */
171         return x - _parent_rectangle.get_x();
172 }
173
174 double
175 PortMatrixRowLabels::component_to_parent_y (double y) const
176 {
177         return y - _body->yoffset() + _parent_rectangle.get_y();
178 }
179
180 double
181 PortMatrixRowLabels::parent_to_component_y (double y) const
182 {
183         return y + _body->yoffset() - _parent_rectangle.get_y();
184 }
185
186
187 double
188 PortMatrixRowLabels::bundle_name_x () const
189 {
190         double x = 0;
191
192         if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && !_matrix->show_only_bundles ()) {
193                 x = _longest_port_name + name_pad() * 2;
194         }
195
196         return x;
197 }
198
199 double
200 PortMatrixRowLabels::port_name_x () const
201 {
202         if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) {
203                 return _longest_bundle_name + name_pad() * 2;
204         } else {
205                 return 0;
206         }
207
208         return 0;
209 }
210
211 void
212 PortMatrixRowLabels::render_bundle_name (
213         cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, boost::shared_ptr<ARDOUR::Bundle> b
214         )
215 {
216         double const x = bundle_name_x ();
217
218         int const n = _matrix->show_only_bundles() ? 1 : _matrix->count_of_our_type (b->nchannels());
219         set_source_rgb (cr, bg_colour);
220         cairo_rectangle (cr, xoff + x, yoff, _longest_bundle_name + name_pad() * 2, grid_spacing() * n);
221         cairo_fill_preserve (cr);
222         set_source_rgb (cr, fg_colour);
223         cairo_set_line_width (cr, label_border_width ());
224         cairo_stroke (cr);
225
226         cairo_text_extents_t ext;
227         cairo_text_extents (cr, b->name().c_str(), &ext);
228         double const off = (grid_spacing() - ext.height) / 2;
229
230         set_source_rgb (cr, text_colour());
231         cairo_move_to (cr, xoff + x + name_pad(), yoff + name_pad() + off);
232         cairo_show_text (cr, b->name().c_str());
233 }
234
235 void
236 PortMatrixRowLabels::render_channel_name (
237         cairo_t* cr, Gdk::Color fg_colour, Gdk::Color bg_colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc
238         )
239 {
240         set_source_rgb (cr, bg_colour);
241         cairo_rectangle (cr, port_name_x() + xoff, yoff, _longest_port_name + name_pad() * 2, grid_spacing());
242         cairo_fill_preserve (cr);
243         set_source_rgb (cr, fg_colour);
244         cairo_set_line_width (cr, label_border_width ());
245         cairo_stroke (cr);
246
247         cairo_text_extents_t ext;
248         cairo_text_extents (cr, bc.bundle->channel_name(bc.channel).c_str(), &ext);
249         double const off = (grid_spacing() - ext.height) / 2;
250
251         if (_matrix->count_of_our_type (bc.bundle->nchannels()) > 1) {
252
253                 /* only plot the name if the bundle has more than one channel;
254                    the name of a single channel is assumed to be redundant */
255
256                 set_source_rgb (cr, text_colour());
257                 cairo_move_to (cr, port_name_x() + xoff + name_pad(), yoff + name_pad() + off);
258                 cairo_show_text (cr, bc.bundle->channel_name(bc.channel).c_str());
259         }
260 }
261
262 double
263 PortMatrixRowLabels::channel_x (ARDOUR::BundleChannel const &) const
264 {
265         return 0;
266 }
267
268 double
269 PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const
270 {
271         return channel_to_position (bc, _matrix->visible_rows()) * grid_spacing ();
272 }
273
274 void
275 PortMatrixRowLabels::queue_draw_for (ARDOUR::BundleChannel const & bc)
276 {
277         if (bc.bundle) {
278
279                 if (_matrix->show_only_bundles()) {
280                         _body->queue_draw_area (
281                                 component_to_parent_x (bundle_name_x()) - 1,
282                                 component_to_parent_y (channel_y (bc)) - 1,
283                                 _longest_bundle_name + name_pad() * 2 + 2,
284                                 grid_spacing() + 2
285                                 );
286                 } else {
287                         _body->queue_draw_area (
288                                 component_to_parent_x (port_name_x()) - 1,
289                                 component_to_parent_y (channel_y (bc)) - 1,
290                                 _longest_port_name + name_pad() * 2 + 2,
291                                 grid_spacing() + 2
292                                 );
293                 }
294         }
295
296 }
297
298 void
299 PortMatrixRowLabels::mouseover_changed (list<PortMatrixNode> const &)
300 {
301         list<PortMatrixNode> const m = _body->mouseover ();
302         for (list<PortMatrixNode>::const_iterator i = m.begin(); i != m.end(); ++i) {
303
304                 ARDOUR::BundleChannel c = i->column;
305                 ARDOUR::BundleChannel r = i->row;
306
307                 if (c.bundle && r.bundle) {
308                         add_channel_highlight (r);
309                 } else if (r.bundle) {
310                         _body->highlight_associated_channels (_matrix->row_index(), r);
311                 }
312         }
313 }
314
315 void
316 PortMatrixRowLabels::motion (double x, double y)
317 {
318         ARDOUR::BundleChannel const w = position_to_channel (y, x, _matrix->visible_rows());
319
320         uint32_t const bw = _longest_bundle_name + 2 * name_pad();
321
322         bool done = false;
323
324         if (w.bundle) {
325
326                 if (
327                         (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x < bw) ||
328                         (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x > (_width - bw) && x < _width)
329
330                         ) {
331
332                         /* if the mouse is over a bundle name, highlight all channels in the bundle */
333
334                         list<PortMatrixNode> n;
335
336                         for (uint32_t i = 0; i < w.bundle->nchannels().n_total(); ++i) {
337
338                                 if (!_matrix->should_show (w.bundle->channel_type(i))) {
339                                         continue;
340                                 }
341
342                                 ARDOUR::BundleChannel const bc (w.bundle, i);
343                                 n.push_back (PortMatrixNode (bc, ARDOUR::BundleChannel ()));
344                         }
345
346                         _body->set_mouseover (n);
347                         done = true;
348
349                 } else if (x < _width) {
350
351                         _body->set_mouseover (PortMatrixNode (w, ARDOUR::BundleChannel ()));
352                         done = true;
353
354                 }
355
356         }
357
358         if (!done) {
359                 /* not over any bundle */
360                 _body->set_mouseover (PortMatrixNode ());
361                 return;
362         }
363 }