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